changeset 21806b909be0 in modules/purchase_secondary_unit:default
details: 
https://hg.tryton.org/modules/purchase_secondary_unit?cmd=changeset&node=21806b909be0
description:
        Add purchase_blanket_agreement and sale_blanket_agreement modules

        issue10962
        review391151002
diffstat:

 __init__.py                                                  |    5 +
 purchase.py                                                  |  110 +++++++++
 setup.py                                                     |    1 +
 tests/scenario_purchase_blanket_agreement_secondary_unit.rst |  133 +++++++++++
 tests/test_module.py                                         |    4 +-
 tryton.cfg                                                   |    1 +
 6 files changed, 253 insertions(+), 1 deletions(-)

diffs (302 lines):

diff -r 7dc49b575e69 -r 21806b909be0 __init__.py
--- a/__init__.py       Mon May 02 17:43:11 2022 +0200
+++ b/__init__.py       Mon Oct 10 18:35:01 2022 +0200
@@ -21,3 +21,8 @@
         purchase.RequisitionLine,
         module='purchase_secondary_unit', type_='model',
         depends=['purchase_requisition'])
+    Pool.register(
+        purchase.BlanketAgreementLine,
+        purchase.LineBlanketAgreement,
+        module='purchase_secondary_unit', type_='model',
+        depends=['purchase_blanket_agreement'])
diff -r 7dc49b575e69 -r 21806b909be0 purchase.py
--- a/purchase.py       Mon May 02 17:43:11 2022 +0200
+++ b/purchase.py       Mon Oct 10 18:35:01 2022 +0200
@@ -238,3 +238,113 @@
                     factor=product.purchase_secondary_uom_normal_rate,
                     rate=product.purchase_secondary_uom_normal_factor))
         return unit_price
+
+
+class BlanketAgreementLine(metaclass=PoolMeta):
+    __name__ = 'purchase.blanket_agreement.line'
+
+    product_secondary_uom_category = fields.Function(
+        fields.Many2One(
+            'product.uom.category', "Product Secondary UOM Category"),
+        'on_change_with_product_secondary_uom_category')
+
+    @classmethod
+    def _unit_categories(cls):
+        return super()._unit_categories() + ['product_secondary_uom_category']
+
+    def is_same_uom_category(self, purchase_line):
+        return super().is_same_uom_category(purchase_line) or (
+            purchase_line.secondary_unit and (
+                self.unit.category == purchase_line.secondary_unit.category))
+
+    def remainig_quantity_for_purchase(self, line, round=True):
+        pool = Pool()
+        Uom = pool.get('product.uom')
+        remaining_quantity = super().remainig_quantity_for_purchase(
+            line, round=round)
+        if (self.remaining_quantity is not None
+                and line.secondary_unit
+                and self.unit.category == line.secondary_unit.category):
+            remaining_quantity = Uom.compute_qty(
+                self.unit, self.remaining_quantity, line.unit,
+                factor=line.secondary_uom_rate,
+                rate=line.secondary_uom_factor,
+                round=round)
+        return remaining_quantity
+
+    @fields.depends('product')
+    def on_change_with_product_secondary_uom_category(self, name=None):
+        if self.product and self.product.purchase_secondary_uom:
+            return self.product.purchase_secondary_uom.category.id
+
+    def _set_purchase_line_quantity(self, purchase_line):
+        super()._set_purchase_line_quantity(purchase_line)
+        secondary_uom = self.product.purchase_secondary_uom
+        if (secondary_uom
+                and self.unit.category == secondary_uom.category):
+            purchase_line.unit = self.product.purchase_uom
+            purchase_line.secondary_quantity = self.remaining_quantity or 0
+            purchase_line.secondary_unit = self.unit
+            purchase_line.secondary_unit_price = self.unit_price
+            purchase_line.on_change_secondary_quantity()
+
+
+class LineBlanketAgreement(metaclass=PoolMeta):
+    __name__ = 'purchase.line'
+
+    @fields.depends(
+        'blanket_agreement_line', '_parent_blanket_agreement_line.unit',
+        '_parent_blanket_agreement_line.unit_price', 'unit', 'secondary_unit')
+    def compute_unit_price(self):
+        pool = Pool()
+        Uom = pool.get('product.uom')
+        unit_price = super().compute_unit_price()
+        line = self.blanket_agreement_line
+        if (line
+                and self.unit
+                and self.secondary_unit
+                and line.unit
+                and self.secondary_unit.category == line.unit.category):
+            secondary_unit_price = Uom.compute_price(
+                line.unit, line.unit_price, self.secondary_unit)
+            unit_price = Uom.compute_price(
+                self.secondary_unit, secondary_unit_price, self.unit,
+                factor=self.secondary_uom_rate, rate=self.secondary_uom_factor)
+            unit_price = round_price(unit_price)
+        return unit_price
+
+    @fields.depends(
+        'blanket_agreement_line',
+        '_parent_blanket_agreement_line.unit',
+        '_parent_blanket_agreement_line.remaining_quantity',
+        'secondary_quantity', 'secondary_unit',
+        methods=['on_change_secondary_quantity'])
+    def on_change_blanket_agreement_line(self):
+        pool = Pool()
+        Uom = pool.get('product.uom')
+        super().on_change_blanket_agreement_line()
+        if self.blanket_agreement_line:
+            line = self.blanket_agreement_line
+            if (self.secondary_unit and line.unit
+                    and self.secondary_unit.category == line.unit.category):
+                if line.remaining_quantity is not None:
+                    remaining_quantity = Uom.compute_qty(
+                        line.unit, line.remaining_quantity,
+                        self.secondary_unit)
+                    if (self.secondary_quantity is None
+                            or self.secondary_quantity > remaining_quantity):
+                        self.secondary_quantity = remaining_quantity
+                        self.on_change_secondary_quantity()
+
+    def quantity_for_blanket_agreement(self, line, round=True):
+        pool = Pool()
+        Uom = pool.get('product.uom')
+        quantity = super().quantity_for_blanket_agreement(line, round=round)
+        if (self.secondary_unit
+                and self.secondary_unit.category == line.unit.category):
+            quantity = Uom.compute_qty(
+                self.unit, (self.actual_quantity or self.quantity), line.unit,
+                factor=self.secondary_uom_factor,
+                rate=self.secondary_uom_rate,
+                round=round)
+        return quantity
diff -r 7dc49b575e69 -r 21806b909be0 setup.py
--- a/setup.py  Mon May 02 17:43:11 2022 +0200
+++ b/setup.py  Mon Oct 10 18:35:01 2022 +0200
@@ -66,6 +66,7 @@
 
 tests_require = [get_require_version('proteus'),
     get_require_version('trytond_account_invoice_secondary_unit'),
+    get_require_version('trytond_purchase_blanket_agreement'),
     get_require_version('trytond_purchase_request'),
     get_require_version('trytond_purchase_requisition'),
     get_require_version('trytond_stock_secondary_unit')]
diff -r 7dc49b575e69 -r 21806b909be0 
tests/scenario_purchase_blanket_agreement_secondary_unit.rst
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/scenario_purchase_blanket_agreement_secondary_unit.rst      Mon Oct 
10 18:35:01 2022 +0200
@@ -0,0 +1,133 @@
+==================================================
+Purchase Blanket Agreement Secondary Unit Scenario
+==================================================
+
+Imports::
+
+    >>> import datetime
+    >>> from dateutil.relativedelta import relativedelta
+    >>> from decimal import Decimal
+
+    >>> from proteus import Model, Wizard
+    >>> from trytond.tests.tools import activate_modules
+    >>> from trytond.modules.company.tests.tools import (
+    ...     create_company, get_company)
+    >>> from trytond.modules.account.tests.tools import (
+    ...     create_chart, get_accounts)
+
+    >>> today = datetime.date.today()
+    >>> later = today + relativedelta(days=30)
+
+
+Activate modules::
+
+    >>> config = activate_modules([
+    ...         'purchase_secondary_unit', 'purchase_blanket_agreement'])
+
+    >>> Party = Model.get('party.party')
+    >>> ProductCategory = Model.get('product.category')
+    >>> ProductUom = Model.get('product.uom')
+    >>> ProductTemplate = Model.get('product.template')
+    >>> PurchaseBlanketAgreement = Model.get('purchase.blanket_agreement')
+
+Create company::
+
+    >>> _ = create_company()
+    >>> company = get_company()
+
+Create chart of accounts::
+
+    >>> _ = create_chart(company)
+    >>> accounts = get_accounts(company)
+
+Create supplier::
+
+    >>> supplier = Party(name="Supplier")
+    >>> supplier.save()
+
+Create account category::
+
+    >>> account_category = ProductCategory(name="Account Category")
+    >>> account_category.accounting = True
+    >>> account_category.account_expense = accounts['expense']
+    >>> account_category.account_revenue = accounts['revenue']
+    >>> account_category.save()
+
+Create product::
+
+    >>> unit, = ProductUom.find([('name', '=', 'Unit')])
+    >>> gr, = ProductUom.find([('name', '=', 'Gram')])
+    >>> template = ProductTemplate()
+    >>> template.name = "Product"
+    >>> template.default_uom = unit
+    >>> template.type = 'goods'
+    >>> template.list_price = Decimal('10.000')
+    >>> template.purchasable = True
+    >>> template.account_category = account_category
+    >>> template.purchase_secondary_uom = gr
+    >>> template.purchase_secondary_uom_factor = 100
+    >>> template.save()
+    >>> product, = template.products
+    >>> product.cost_price = Decimal('8.000')
+    >>> product.save()
+
+Create purchase blanket agreement::
+
+    >>> blanket_agreement = PurchaseBlanketAgreement()
+    >>> blanket_agreement.supplier = supplier
+    >>> blanket_agreement.from_date = today
+    >>> blanket_agreement.to_date = later
+    >>> blanket_agreement_line = blanket_agreement.lines.new()
+    >>> blanket_agreement_line.product = product
+    >>> blanket_agreement_line.quantity = 800.0
+    >>> blanket_agreement_line.unit = gr
+    >>> blanket_agreement_line.unit_price = Decimal('7.000')
+    >>> blanket_agreement.click('run')
+    >>> blanket_agreement.state
+    'running'
+
+Create purchase from blanket agreement::
+
+    >>> create_purchase = Wizard(
+    ...     'purchase.blanket_agreement.create_purchase', [blanket_agreement])
+    >>> create_purchase.form.lines[0].unit == gr
+    True
+    >>> create_purchase.execute('create_purchase')
+
+    >>> purchase, = create_purchase.actions[0]
+    >>> line, = purchase.lines
+    >>> line.product == product
+    True
+
+    >>> line.secondary_unit == gr
+    True
+    >>> line.secondary_quantity
+    800.0
+    >>> line.secondary_unit_price
+    Decimal('7.0000')
+
+    >>> line.unit == unit
+    True
+    >>> line.quantity
+    8.0
+    >>> line.unit_price
+    Decimal('700.0000')
+
+    >>> line.secondary_quantity = 300.0
+    >>> purchase.save()
+
+    >>> blanket_agreement.reload()
+    >>> blanket_agreement_line, = blanket_agreement.lines
+    >>> blanket_agreement_line.remaining_quantity
+    800.0
+
+Confirm purchase::
+
+    >>> purchase.click('quote')
+    >>> purchase.click('confirm')
+    >>> purchase.state
+    'processing'
+
+    >>> blanket_agreement_line.reload()
+    >>> blanket_agreement_line.remaining_quantity
+    500.0
diff -r 7dc49b575e69 -r 21806b909be0 tests/test_module.py
--- a/tests/test_module.py      Mon May 02 17:43:11 2022 +0200
+++ b/tests/test_module.py      Mon Oct 10 18:35:01 2022 +0200
@@ -7,7 +7,9 @@
 class PurchaseSecondaryUnitTestCase(ModuleTestCase):
     'Test Purchase Secondary Unit module'
     module = 'purchase_secondary_unit'
-    extras = ['account_invoice_secondary_unit', 'stock_secondary_unit']
+    extras = [
+        'account_invoice_secondary_unit', 'stock_secondary_unit',
+        'purchase_blanket_agreement']
 
 
 del ModuleTestCase
diff -r 7dc49b575e69 -r 21806b909be0 tryton.cfg
--- a/tryton.cfg        Mon May 02 17:43:11 2022 +0200
+++ b/tryton.cfg        Mon Oct 10 18:35:01 2022 +0200
@@ -8,6 +8,7 @@
     stock
 extras_depend:
     account_invoice_secondary_unit
+    purchase_blanket_agreement
     purchase_requisition
     stock_secondary_unit
 xml:

Reply via email to