Merge pull request #14 from bakeupboys/39-16.0-add_credit_to_webshop

[imp] add nfu_ecommerce module, add balance to cart
This commit is contained in:
madmooose 2024-07-28 22:28:14 +02:00 committed by GitHub
commit b8bb1e3596
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 250 additions and 479 deletions

View file

@ -1,6 +1,6 @@
==========================
NFU Sale Min Max Quantitiy
==========================
=============
NFU eCommerce
=============
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@ -17,12 +17,15 @@ NFU Sale Min Max Quantitiy
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-bruecksen%2Fife_nfu-lightgray.png?logo=github
:target: https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_product_min_max_qty
:target: https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_ecommerce
:alt: bruecksen/ife_nfu
|badge1| |badge2| |badge3|
This module adds a minium and a maximum order quantity field to Sale Orders and adds it to checkout of the website shop.
This module adds a maximum order quantity field to Website Sale Orders. It also adds
an ordered qantitiy field to store the original ordered quantity in case a manager
adjustes the uom quantitiy. In webshop checkout it adds the customer balance to before
and after the current order.
**Table of contents**
@ -32,7 +35,7 @@ This module adds a minium and a maximum order quantity field to Sale Orders and
Changelog
=========
:1.0.0: Initial module.
:0.0.1: Initial module.
Bug Tracker
===========
@ -40,7 +43,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/bruecksen/ife_nfu/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/bruecksen/ife_nfu/issues/new?body=module:%20nfu_sale_product_min_max_qty%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
`feedback <https://github.com/bruecksen/ife_nfu/issues/new?body=module:%20nfu_ecommerce%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
@ -61,6 +64,6 @@ Contributors
Maintainers
~~~~~~~~~~~
This module is part of the `bruecksen/ife_nfu <https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_product_min_max_qty>`_ project on GitHub.
This module is part of the `bruecksen/ife_nfu <https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_ecommerce>`_ project on GitHub.
You are welcome to contribute.

View file

@ -1,3 +1,2 @@
from . import models
from . import controllers
from . import wizard

View file

@ -0,0 +1,12 @@
{
"name": "NFU eCommerce",
"summary": "Qty ranges, packagings and credit in webshop",
"author": "BAKEUP",
"website": "https://www.bakeup.org",
"category": "website",
"version": "16.0.0.0.1",
"depends": ["website_sale", "nfu_sale_order_batch_packaging"],
"data": ["views/templates.xml"],
"assets": {"web.assets_frontend": ["nfu_ecommerce/static/src/js/website_sale.js"]},
"license": "LGPL-3",
}

View file

@ -0,0 +1 @@
from . import main

View file

@ -0,0 +1,12 @@
from odoo import fields, http
from odoo.addons.website_sale.controllers.main import WebsiteSale
class WebsiteSaleMinMax(WebsiteSale):
@http.route()
def cart_update(self, *args, ordered_qty=None, max_qty=None, **kw):
"""Override to get ordered_qty and max_qty from the product."""
product_uom_ordered_qty = fields.Float(ordered_qty)
product_uom_max_qty = fields.Float(max_qty)
return super().cart_update(*args, ordered_qty=product_uom_ordered_qty, max_qty=product_uom_max_qty, **kw)

View file

@ -0,0 +1 @@
from . import sale_order

View file

@ -0,0 +1,49 @@
from odoo import api, fields, models
class SaleOrder(models.Model):
_inherit = "sale.order"
balance = fields.Monetary(compute="_compute_balance")
updated_balance = fields.Monetary(compute="_compute_updated_balance")
def _compute_balance(self):
for order in self:
order.balance = -order.partner_id.commercial_partner_id.credit
@api.depends("amount_total")
def _compute_updated_balance(self):
for order in self:
order.updated_balance = order.balance - (order.amount_total / order.currency_rate)
def _prepare_order_line_values(
self,
product_id,
quantity,
linked_line_id=False,
no_variant_attribute_values=None,
product_custom_attribute_values=None,
**kwargs
):
values = super()._prepare_order_line_values(
product_id,
quantity,
linked_line_id=linked_line_id,
no_variant_attribute_values=no_variant_attribute_values,
product_custom_attribute_values=product_custom_attribute_values,
**kwargs
)
values.update({"product_uom_ordered_qty": quantity, "product_uom_max_qty": kwargs.get("max_qty", quantity)})
return values
def _prepare_order_line_update_values(self, order_line, quantity, linked_line_id=False, **kwargs):
values = super()._prepare_order_line_update_values(
order_line, quantity, linked_line_id=linked_line_id, **kwargs
)
max_qty = kwargs.get("max_qty", quantity)
if quantity != order_line.product_uom_ordered_qty:
values["product_uom_ordered_qty"] = quantity
if max_qty and max_qty != order_line.product_uom_max_qty:
values["product_uom_max_qty"] = max_qty
return values

View file

@ -0,0 +1,4 @@
This module adds a maximum order quantity field to Website Sale Orders. It also adds
an ordered qantitiy field to store the original ordered quantity in case a manager
adjustes the uom quantitiy. In webshop checkout it adds the customer balance to before
and after the current order.

View file

@ -0,0 +1 @@
:0.0.1: Initial module.

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>NFU Sale Min Max Quantitiy</title>
<title>NFU eCommerce</title>
<style type="text/css">
/*
@ -360,8 +360,8 @@ ul.auto-toc {
</style>
</head>
<body>
<div class="document" id="nfu-sale-min-max-quantitiy">
<h1 class="title">NFU Sale Min Max Quantitiy</h1>
<div class="document" id="nfu-ecommerce">
<h1 class="title">NFU eCommerce</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
@ -369,8 +369,11 @@ ul.auto-toc {
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:4dfaea54e4d01502b433eb5c0dcca409a5fbe2c3f175e29382a19230343183c9
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_product_min_max_qty"><img alt="bruecksen/ife_nfu" src="https://img.shields.io/badge/github-bruecksen%2Fife_nfu-lightgray.png?logo=github" /></a></p>
<p>This module adds a minium and a maximum order quantity field to Sale Orders and adds it to checkout of the website shop.</p>
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_ecommerce"><img alt="bruecksen/ife_nfu" src="https://img.shields.io/badge/github-bruecksen%2Fife_nfu-lightgray.png?logo=github" /></a></p>
<p>This module adds a maximum order quantity field to Website Sale Orders. It also adds
an ordered qantitiy field to store the original ordered quantity in case a manager
adjustes the uom quantitiy. In webshop checkout it adds the customer balance to before
and after the current order.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
@ -390,7 +393,7 @@ ul.auto-toc {
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">1.0.0:</th><td class="field-body">Initial module.</td>
<tr class="field"><th class="field-name">0.0.1:</th><td class="field-body">Initial module.</td>
</tr>
</tbody>
</table>
@ -400,7 +403,7 @@ ul.auto-toc {
<p>Bugs are tracked on <a class="reference external" href="https://github.com/bruecksen/ife_nfu/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/bruecksen/ife_nfu/issues/new?body=module:%20nfu_sale_product_min_max_qty%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<a class="reference external" href="https://github.com/bruecksen/ife_nfu/issues/new?body=module:%20nfu_ecommerce%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
@ -420,7 +423,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is part of the <a class="reference external" href="https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_product_min_max_qty">bruecksen/ife_nfu</a> project on GitHub.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_ecommerce">bruecksen/ife_nfu</a> project on GitHub.</p>
<p>You are welcome to contribute.</p>
</div>
</div>

View file

@ -1,36 +1,10 @@
odoo.define("nfu_sale_product_min_max_qty.website_min_max_qty", function (require) {
odoo.define("nfu_ecommerce.website_max_qty", function (require) {
"use strict";
var core = require("web.core");
var _t = core._t;
var wSaleUtils = require("website_sale.utils");
var publicWidget = require("web.public.widget");
require("website_sale.website_sale");
publicWidget.registry.WebsiteSale.include({
onClickAddCartJSON: function (ev) {
ev.preventDefault();
$(".css_quantity").popover("dispose");
var $link = $(ev.currentTarget);
var $input = $link.closest(".input-group").find("input");
var min = parseFloat($input.data("min") || 0);
var previousQty = parseFloat($input.val() || 0, 10);
var quantity = ($link.has(".fa-minus").length ? -1 : 1) + previousQty;
if (quantity < min) {
$input.closest(".css_quantity").popover({
content: _t(`Minimum Quantity is ${min}.`),
title: _t("Warning"),
placement: "left",
trigger: "focus",
html: true,
});
$input.closest(".css_quantity").popover("show");
setTimeout(function () {
$(".css_quantity").popover("dispose");
}, 3000);
}
this._super(ev);
},
/**
* Adds the max qty to the POST request when adding a product to the cart.
* @override

View file

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="cart_lines_max_qty" inherit_id="website_sale.cart_lines" name="Shopping Cart Lines">
<xpath expr="//th[hasclass('td-qty')]" position="after">
<th class="text-center td-qty">
<t t-if="show_qty">
<span>Max Qty</span>
</t>
</th>
</xpath>
<xpath expr="//td[hasclass('td-qty')]" position="after">
<td class="text-center td-qty">
<div class="css_quantity input-group mx-auto justify-content-center">
<t t-if="not line._is_not_sellable_line()">
<t t-if="show_qty">
<a
t-attf-href="#"
class="btn btn-link js_add_cart_json d-none d-md-inline-block"
aria-label="Remove one"
title="Remove one"
>
<i class="fa fa-minus"/>
</a>
<input
type="text"
name="max-qty"
class="js_quantity form-control quantity"
t-att-data-line-id="line.id"
t-att-data-product-id="line.product_id.id"
t-att-value="line.product_uom_max_qty and int(line.product_uom_max_qty) or int(line.product_uom_qty)"
t-att-data-min="int(line.product_uom_qty)"
/>
<t t-if="line._get_shop_warning(clear=False)">
<a t-attf-href="#" class="btn btn-link">
<i
class='fa fa-warning text-warning'
t-att-title="line._get_shop_warning()"
role="img"
aria-label="Warning"
/>
</a>
</t>
<a
t-else=''
t-attf-href="#"
class="btn btn-link float_left js_add_cart_json d-none d-md-inline-block"
aria-label="Add one"
title="Add one"
>
<i class="fa fa-plus"/>
</a>
</t>
<t t-else="">
<input
type="hidden"
class="js_quantity form-control quantity"
t-att-data-line-id="line.id"
t-att-data-product-id="line.product_id.id"
t-att-value="int(line.product_uom_qty) == line.product_uom_qty and int(line.product_uom_qty) or line.product_uom_qty"
/>
</t>
</t>
<t t-else="">
<span class="text-muted w-100" t-esc="int(line.product_uom_qty)"/>
<input
type="hidden"
class="js_quantity form-control quantity"
t-att-data-line-id="line.id"
t-att-data-product-id="line.product_id.id"
t-att-value="line.product_uom_qty"
/>
</t>
</div>
</td>
</xpath>
</template>
<template id="cart_summary_max_qty" inherit_id="website_sale.cart_summary" name="Cart right column">
<xpath expr="//th[hasclass('td-qty')]" position="after">
<th class="border-top-0 td-qty">Max Qty</th>
</xpath>
<xpath expr="//td[hasclass('td-qty')]" position="after">
<td class='td-qty'>
<div t-esc="line.product_uom_max_qty"/>
</td>
</xpath>
</template>
<template id="total" inherit_id="website_sale.total">
<xpath expr="//tr[@id='empty']" position="after">
<tr id="balance">
<td class="text-end border-0">Balance:</td>
<td class="text-xl-end border-0">
<span
t-field="website_sale_order.balance"
class="monetary_field"
style="white-space: nowrap;"
t-options="{'widget': 'monetary', 'display_currency': website_sale_order.currency_id}"
/>
</td>
</tr>
</xpath>
<xpath expr="//tr[@id='order_total']" position="after">
<tr id="updated_balance">
<td class="text-end border-0">New balance:</td>
<td class="text-xl-end border-0">
<t t-if="website_sale_order.updated_balance &lt; 0">
<span
t-field="website_sale_order.updated_balance"
class="monetary_field text-danger"
style="white-space: nowrap;"
t-options="{'widget': 'monetary', 'display_currency': website_sale_order.currency_id}"
/>
</t>
<t t-else="">
<span
t-field="website_sale_order.updated_balance"
t-att-class="monetary_field"
style="white-space: nowrap;"
t-options="{'widget': 'monetary', 'display_currency': website_sale_order.currency_id}"
/>
</t>
</td>
</tr>
</xpath>
</template>
</odoo>

View file

@ -1,6 +1,6 @@
========================
NFU Sale Order Packaging
========================
==============================
NFU Sale Order Batch Packaging
==============================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@ -17,7 +17,7 @@ NFU Sale Order Packaging
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-bruecksen%2Fife_nfu-lightgray.png?logo=github
:target: https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_order_packaging
:target: https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_order_batch_packaging
:alt: bruecksen/ife_nfu
|badge1| |badge2| |badge3|
@ -33,7 +33,8 @@ and adds a packaging default to sale order batch.
Changelog
=========
:1.0.0: Initial module.
:0.0.1: Initial module.
:1.0.0: rename to nfu_sale_order_batch_packaging
Bug Tracker
===========
@ -41,7 +42,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/bruecksen/ife_nfu/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/bruecksen/ife_nfu/issues/new?body=module:%20nfu_sale_order_packaging%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
`feedback <https://github.com/bruecksen/ife_nfu/issues/new?body=module:%20nfu_sale_order_batch_packaging%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
@ -62,6 +63,6 @@ Contributors
Maintainers
~~~~~~~~~~~
This module is part of the `bruecksen/ife_nfu <https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_order_packaging>`_ project on GitHub.
This module is part of the `bruecksen/ife_nfu <https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_order_batch_packaging>`_ project on GitHub.
You are welcome to contribute.

View file

@ -1,10 +1,10 @@
{
"name": "NFU Sale Order Packaging",
"summary": "Add minimum and maximum order quantities to sale orders and use default packaging",
"name": "NFU Sale Order Batch Packaging",
"summary": "Add minimum and maximum order quantities to sale orders and batches and use default packaging",
"author": "BAKEUP",
"website": "https://www.bakeup.org",
"category": "Sale",
"version": "16.0.0.0.1",
"version": "16.0.1.0.0",
"depends": ["sale", "sale_order_batch"],
"data": [
"views/sale_order_views.xml",

View file

@ -0,0 +1,2 @@
:0.0.1: Initial module.
:1.0.0: rename to nfu_sale_order_batch_packaging

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>NFU Sale Order Packaging</title>
<title>NFU Sale Order Batch Packaging</title>
<style type="text/css">
/*
@ -360,8 +360,8 @@ ul.auto-toc {
</style>
</head>
<body>
<div class="document" id="nfu-sale-order-packaging">
<h1 class="title">NFU Sale Order Packaging</h1>
<div class="document" id="nfu-sale-order-batch-packaging">
<h1 class="title">NFU Sale Order Batch Packaging</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
@ -369,7 +369,7 @@ ul.auto-toc {
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:cf35c3a80aa0718148099036cd6a3dd60afb61acdb420573b1bd129be3ea2cf1
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_order_packaging"><img alt="bruecksen/ife_nfu" src="https://img.shields.io/badge/github-bruecksen%2Fife_nfu-lightgray.png?logo=github" /></a></p>
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_order_batch_packaging"><img alt="bruecksen/ife_nfu" src="https://img.shields.io/badge/github-bruecksen%2Fife_nfu-lightgray.png?logo=github" /></a></p>
<p>This module adds a minium and a maximum order quantity field to Sale Orders
and adds a packaging default to sale order batch.</p>
<p><strong>Table of contents</strong></p>
@ -391,7 +391,9 @@ and adds a packaging default to sale order batch.</p>
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">1.0.0:</th><td class="field-body">Initial module.</td>
<tr class="field"><th class="field-name">0.0.1:</th><td class="field-body">Initial module.</td>
</tr>
<tr class="field"><th class="field-name">1.0.0:</th><td class="field-body">rename to nfu_sale_order_batch_packaging</td>
</tr>
</tbody>
</table>
@ -401,7 +403,7 @@ and adds a packaging default to sale order batch.</p>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/bruecksen/ife_nfu/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/bruecksen/ife_nfu/issues/new?body=module:%20nfu_sale_order_packaging%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<a class="reference external" href="https://github.com/bruecksen/ife_nfu/issues/new?body=module:%20nfu_sale_order_batch_packaging%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
@ -421,7 +423,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is part of the <a class="reference external" href="https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_order_packaging">bruecksen/ife_nfu</a> project on GitHub.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/bruecksen/ife_nfu/tree/16.0/nfu_sale_order_batch_packaging">bruecksen/ife_nfu</a> project on GitHub.</p>
<p>You are welcome to contribute.</p>
</div>
</div>

View file

@ -1 +0,0 @@
:1.0.0: Initial module.

View file

@ -1,19 +0,0 @@
{
"name": "NFU Sale Min Max Quantitiy",
"summary": "Add minimum and maximum order quantities to sale orders",
"author": "BAKEUP",
"website": "https://www.bakeup.org",
"category": "Stock",
"version": "16.0.0.0.1",
"depends": ["sale_management", "website_sale"],
"data": [
"views/sale_order_views.xml",
"views/sale_order_line_views.xml",
"wizard/sale_max_qty_line_views.xml",
"wizard/sale_max_qty_chooser_views.xml",
"views/templates.xml",
"security/ir.model.access.csv",
],
"assets": {"web.assets_frontend": ["nfu_sale_product_min_max_qty/static/src/js/website_sale.js"]},
"license": "LGPL-3",
}

View file

@ -1 +0,0 @@
from . import main

View file

@ -1,16 +0,0 @@
# -*- coding: utf-8 -*-
from odoo.http import request
from odoo import fields, http
from odoo.addons.website_sale.controllers.main import WebsiteSale
class WebsiteSaleMinMax(WebsiteSale):
@http.route()
def cart_update(self, *args, min_qty=None, max_qty=None, **kw):
""" Override to get min_qty and max_qty from the product.
"""
product_uom_min_qty = fields.Float(min_qty)
product_uom_max_qty = fields.Float(max_qty)
return super().cart_update(*args, min_qty=product_uom_min_qty, max_qty=product_uom_max_qty, **kw)

View file

@ -1,2 +0,0 @@
from . import sale_order_line
from . import sale_order

View file

@ -1,80 +0,0 @@
from odoo import _, models
class SaleOrder(models.Model):
_inherit = "sale.order"
def action_min_max_qty_wizard(self):
"""
Here you need to create the wizzard objects first and then call the wizzard with the newly created id
"""
sale_max_qty_chooser = self.env["sale.max.qty.chooser"].create({})
draft_sale_orders = self.filtered(lambda x: x.state == "draft")
for sale_order in draft_sale_orders:
sale_max_qty_chooser.sale_order_ids += sale_order
for line in sale_order.order_line.filtered(lambda x: not x.display_type):
self.env["sale.max.qty.line"].create(
{
"sale_line_id": line.id,
"sale_max_qty_chooser": sale_max_qty_chooser.id,
"qty": line.product_uom_qty,
}
)
action = {
"name": _("Min max qty wizard"),
"type": "ir.actions.act_window",
"res_model": "sale.max.qty.line",
"view_mode": "tree",
"target": "current",
"editable": True,
"context": {"search_default_group_by_product": 1},
"domain": [("id", "in", sale_max_qty_chooser.sale_max_qty_ids.ids)],
}
return action
def action_sale_order_lines(self):
"""
Here you need to create the wizzard objects first and then call the wizzard with the newly created id
"""
return {
"name": _("Min max qty wizard"),
"type": "ir.actions.act_window",
"res_model": "sale.order.line",
"view_mode": "tree,form",
"target": "current",
"context": {"group_by": "product_id"},
"domain": [("id", "in", self.order_line.ids)],
}
def _prepare_order_line_values(
self,
product_id,
quantity,
linked_line_id=False,
no_variant_attribute_values=None,
product_custom_attribute_values=None,
**kwargs
):
values = super()._prepare_order_line_values(
product_id,
quantity,
linked_line_id=linked_line_id,
no_variant_attribute_values=no_variant_attribute_values,
product_custom_attribute_values=product_custom_attribute_values,
**kwargs
)
values.update({"product_uom_min_qty": quantity, "product_uom_max_qty": kwargs.get("max_qty", quantity)})
return values
def _prepare_order_line_update_values(self, order_line, quantity, linked_line_id=False, **kwargs):
values = super()._prepare_order_line_update_values(
order_line, quantity, linked_line_id=linked_line_id, **kwargs
)
max_qty = kwargs.get("max_qty", quantity)
if quantity != order_line.product_uom_min_qty:
values["product_uom_min_qty"] = quantity
if max_qty and max_qty != order_line.product_uom_max_qty:
values["product_uom_max_qty"] = max_qty
return values

View file

@ -1,15 +0,0 @@
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class SaleOrderLine(models.Model):
_inherit = "sale.order.line"
product_uom_min_qty = fields.Float(string="Min qty.", digits="Product Unit of Measure")
product_uom_max_qty = fields.Float(string="Max qty.", digits="Product Unit of Measure")
@api.constrains("product_uom_qty", "product_uom_max_qty")
def _check_product_uom_qty(self):
for record in self:
if record.product_uom_max_qty != 0 and record.product_uom_qty > record.product_uom_max_qty:
raise UserError(_("The quantity must be less than or equal to the maximum quantity."))

View file

@ -1 +0,0 @@
This module adds a minium and a maximum order quantity field to Sale Orders and adds it to checkout of the website shop.

View file

@ -1 +0,0 @@
:1.0.0: Initial module.

View file

@ -1,3 +0,0 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sale_max_qty_chooser,sale.max.qty.chooser,model_sale_max_qty_chooser,sales_team.group_sale_salesman,1,1,1,1
access_sale_max_qty_line,sale.max.qty.line,model_sale_max_qty_line,sales_team.group_sale_salesman,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sale_max_qty_chooser sale.max.qty.chooser model_sale_max_qty_chooser sales_team.group_sale_salesman 1 1 1 1
3 access_sale_max_qty_line sale.max.qty.line model_sale_max_qty_line sales_team.group_sale_salesman 1 1 1 1

View file

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_order_line_tree" model="ir.ui.view">
<field name="name">sale.order.line.tree</field>
<field name="model">sale.order.line</field>
<field name="arch" type="xml">
<tree create="false" expand="1">
<field name="order_id"/>
<field name="order_partner_id"/>
<field name="name"/>
<field name="salesman_id"/>
<field name="product_uom_qty" string="Qty"/>
<field name="product_uom_min_qty" optional="hide"/>
<field name="product_uom_max_qty"/>
<field name="qty_delivered"/>
<field name="qty_invoiced"/>
<field name="qty_to_invoice"/>
<field name="product_uom" string="Unit of Measure" groups="uom.group_uom"/>
<field name="price_subtotal" sum="Total" widget="monetary"/>
<field name="currency_id" invisible="1"/>
</tree>
</field>
</record>
</odoo>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_order_form_inherit_product_min_max_qty" model="ir.ui.view">
<field name="name">sale.order.form.product.min_max_qty</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='order_line']/tree/field[@name='product_uom_qty']" position="after">
<field name="product_uom_min_qty" optional="hide"/>
<field name="product_uom_max_qty"/>
</xpath>
</field>
</record>
<record id="view_order_list_inherit_product_min_max_qty" model="ir.ui.view">
<field name="name">sale.order.list.view.inherited</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_quotation_tree"/>
<field name="arch" type="xml">
<xpath expr="//tree" position="inside">
<header>
<button type="object" name="action_min_max_qty_wizard" string="Min/Max Wizard"/>
<button type="object" name="action_sale_order_lines" string="Sale order lines"/>
</header>
</xpath>
</field>
</record>
</odoo>

View file

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="cart_lines_min_max_qty" inherit_id="website_sale.cart_lines" name="Shopping Cart Lines">
<xpath expr="//th[hasclass('td-qty')]" position="after">
<th class="text-center td-qty">
<t t-if="show_qty">
<span>Max qty.</span>
</t>
</th>
</xpath>
<xpath expr="//td[hasclass('td-qty')]" position="after">
<td class="text-center td-qty">
<div class="css_quantity input-group mx-auto justify-content-center">
<t t-if="not line._is_not_sellable_line()">
<t t-if="show_qty">
<a t-attf-href="#" class="btn btn-link js_add_cart_json d-none d-md-inline-block" aria-label="Remove one" title="Remove one">
<i class="fa fa-minus"></i>
</a>
<input type="text" name="max-qty" class="js_quantity form-control quantity" t-att-data-line-id="line.id" t-att-data-product-id="line.product_id.id" t-att-value="line.product_uom_max_qty and int(line.product_uom_max_qty) or int(line.product_uom_qty)" t-att-data-min="int(line.product_uom_qty)" />
<t t-if="line._get_shop_warning(clear=False)">
<a t-attf-href="#" class="btn btn-link">
<i class='fa fa-warning text-warning' t-att-title="line._get_shop_warning()" role="img" aria-label="Warning"/>
</a>
</t>
<a t-else='' t-attf-href="#" class="btn btn-link float_left js_add_cart_json d-none d-md-inline-block" aria-label="Add one" title="Add one">
<i class="fa fa-plus"></i>
</a>
</t>
<t t-else="">
<input type="hidden" class="js_quantity form-control quantity" t-att-data-line-id="line.id" t-att-data-product-id="line.product_id.id" t-att-value="int(line.product_uom_qty) == line.product_uom_qty and int(line.product_uom_qty) or line.product_uom_qty" />
</t>
</t>
<t t-else="">
<span class="text-muted w-100" t-esc="int(line.product_uom_qty)"/>
<input type="hidden" class="js_quantity form-control quantity" t-att-data-line-id="line.id" t-att-data-product-id="line.product_id.id" t-att-value="line.product_uom_qty" />
</t>
</div>
</td>
</xpath>
</template>
<template id="cart_summary_min_max_qty" inherit_id="website_sale.cart_summary" name="Cart right column">
<xpath expr="//th[hasclass('td-qty')]" position="after">
<th class="border-top-0 td-qty">Max qty.</th>
</xpath>
<xpath expr="//td[hasclass('td-qty')]" position="after">
<td class='td-qty'>
<div t-esc="line.product_uom_max_qty" />
</td>
</xpath>
</template>
</odoo>

View file

@ -1,2 +0,0 @@
from . import sale_max_qty_chooser
from . import sale_max_qty_line

View file

@ -1,54 +0,0 @@
from odoo import fields, models
class SaleMaxQtyChooser(models.TransientModel):
"""Wizard to Allow user to adjust the sale order amout to fit to a packaging size"""
_name = "sale.max.qty.chooser"
_description = "Sale Max Quantity Chhooser"
# fill from init or compute from given sale order lines
sale_order_ids = fields.Many2many("sale.order")
sale_max_qty_ids = fields.One2many("sale.max.qty.line", "sale_max_qty_chooser")
def update_and_confirm_sale_order(self):
"""
Confirm sale orders where the quantity is fine. Create new Sale Orders for SO Lines with reset to draft
Through user error when total order amount of a product is not equal to packaging size (first package in the
list or smalles package sale_order_line.product_id.product.packaging_ids.qty)
we can use write({'key':'value'}) to update all sale order lines and action_confirm() to validate all sale
orders
Also see this methode on how to create new records. It creates a invoice with invoice lines. we need to do the
same for sale orders
def action_sold(self):
res = super().action_sold()
self.env["account.move"].create(
{
"property_id": self.id,
"partner_id": self.buyer_id.id,
"move_type": "out_invoice",
"line_ids": [
fields.Command.create(
{
"name": f"Property {self.name} - 10% Tax",
"quantity": 1,
"price_unit": self.selling_price * 1.1,
}
),
fields.Command.create({"name": "Administration Fees", "quantity": 1, "price_unit": 1000}),
],
}
)
return res
"""
for sale_order in self.sale_order_ids:
can_confirm = True
for line in self.sale_max_qty_ids.filtered(lambda line: line.sale_line_id.order_id == sale_order):
line.sale_line_id.write({"product_uom_qty": line.qty})
if not line.quantity_fits_packaging:
can_confirm = False
if can_confirm:
sale_order.action_confirm()

View file

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_sale_max_qty_chooser_form" model="ir.ui.view">
<field name="name">Sale Max Quantity Chhooser</field>
<field name="model">sale.max.qty.chooser</field>
<field name="arch" type="xml">
<form>
<div class="oe_grey">
<p>Sale Orders</p>
<field name="sale_order_ids" widget="many2many_tags"/>
</div>
<field name="sale_max_qty_ids" context="{'search_default_group_by_qty': 1}">
<!-- <tree create="0" editable="1" default_order="product_id">
<field name="product_id" context="{'group_by': 'product_id'}" />
<field name="qty"/>
<field name="max_qty"/>
<field name="packaging_size"/>
<field name="quantity_fits_packaging" widget="boolean"/>
<field name="reset_to_draft"/>
</tree> -->
</field>
<footer>
<button
name="update_and_confirm_sale_order"
string="Confirm Sale Orders"
type="object"
class="btn-primary"
data-hotkey="q"
/>
<button string="Cancel" class="btn-secondary" special="cancel" data-hotkey="z"/>
</footer>
</form>
</field>
</record>
<record id="action_sale_max_qty" model="ir.actions.act_window">
<field name="name">Set Quantities</field>
<field name="res_model">sale.max.qty.chooser</field>
<field name="view_mode">form</field>
<field name="target">current</field>
<field name="context">
{
'search_default_group_by_product': 1,
}
</field>
</record>
</odoo>

View file

@ -1,46 +0,0 @@
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class SaleMaxQtyLine(models.TransientModel):
"""
Lines to shown in Wizard
"""
_name = "sale.max.qty.line"
_description = "Max qty Sale Order Lines"
name = fields.Char()
sale_max_qty_chooser = fields.Many2one("sale.max.qty.chooser")
qty = fields.Float()
max_qty = fields.Float(related="sale_line_id.product_uom_max_qty")
packaging_size = fields.Float(compute="_compute_packaging_size")
quantity_fits_packaging = fields.Boolean(compute="_compute_quantity_fits_packaging")
total_quantity = fields.Float(compute="_compute_quantity_fits_packaging")
sale_line_id = fields.Many2one("sale.order.line")
product_id = fields.Many2one(related="sale_line_id.product_id", store=True)
reset_to_draft = fields.Boolean()
def _compute_packaging_size(self):
for max_qty_line in self:
max_qty_line.packaging_size = min(
max_qty_line.sale_line_id.product_id.packaging_ids.mapped("qty"), default=1.0
)
@api.onchange("qty")
def _compute_quantity_fits_packaging(self):
for max_qty_line in self:
order_lines = max_qty_line.sale_max_qty_chooser.sale_max_qty_ids.filtered(
lambda line: line.sale_line_id.product_id == max_qty_line.product_id
)
max_qty_line.total_quantity = sum(order_lines.mapped("qty"))
max_qty_line.quantity_fits_packaging = max_qty_line.total_quantity % max_qty_line.packaging_size == 0
# for order_line in order_lines:
# order_line.quantity_fits_packaging = max_qty_line.quantity_fits_packaging
@api.constrains("qty")
def _check_product_uom_qty(self):
for max_qty_line in self:
if max_qty_line.max_qty != 0 and max_qty_line.qty > max_qty_line.max_qty:
raise UserError(_("The quantity must be less than or equal to the maximum quantity."))

View file

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_sale_max_qty_line_search" model="ir.ui.view">
<field name="name">sale.max.qty.line.search</field>
<field name="model">sale.max.qty.line</field>
<field name="arch" type="xml">
<search>
<filter string="Product" name="group_by_product" context="{'group_by':'product_id'}"/>
</search>
</field>
</record>
<record id="viw_sale_max_qty_line_tree" model="ir.ui.view">
<field name="name">sale.max.qty.line.tree</field>
<field name="model">sale.max.qty.line</field>
<field name="arch" type="xml">
<tree editable="bottom" create="0" expand="1">
<field name="product_id"/>
<field name="qty"/>
<field name="max_qty"/>
<field name="packaging_size"/>
<field name="quantity_fits_packaging" widget="boolean"/>
<field name="reset_to_draft"/>
</tree>
</field>
</record>
</odoo>