diff --git a/modules/purchase/purchase.py b/modules/purchase/purchase.py index 50f0424410..ec56f2e8fb 100644 --- a/modules/purchase/purchase.py +++ b/modules/purchase/purchase.py @@ -828,12 +828,16 @@ class Purchase( def is_done(self): return ((self.invoice_state == 'paid' or (self.invoice_state == 'none' - and all(not l.quantity - for l in self.lines if l.type == 'line'))) + and all( + l.invoice_progress >= 1 + for l in self.lines + if l.invoice_progress is not None))) and (self.shipment_state == 'received' or (self.shipment_state == 'none' - and all(l.product.type == 'service' - for l in self.lines if l.product)))) + and all( + l.moves_progress >= 1 + for l in self.lines + if l.moves_progress is not None)))) @classmethod def delete(cls, purchases): diff --git a/modules/purchase/tests/scenario_purchase_line_cancelled.rst b/modules/purchase/tests/scenario_purchase_line_cancelled.rst new file mode 100644 index 0000000000..8430d14072 --- /dev/null +++ b/modules/purchase/tests/scenario_purchase_line_cancelled.rst @@ -0,0 +1,107 @@ +================================ +Purchase Line Cancelled Scenario +================================ + +Imports:: + + >>> from decimal import Decimal + + >>> from proteus import Model + >>> from trytond.tests.tools import activate_modules + >>> from trytond.modules.company.tests.tools import create_company + >>> from trytond.modules.account.tests.tools import ( + ... create_chart, get_accounts) + +Activate modules:: + + >>> config = activate_modules('purchase') + + >>> Party = Model.get('party.party') + >>> ProductCategory = Model.get('product.category') + >>> ProductTemplate = Model.get('product.template') + >>> ProductUom = Model.get('product.uom') + >>> Purchase = Model.get('purchase.purchase') + +Create company:: + + >>> _ = create_company() + +Create chart of accounts:: + + >>> _ = create_chart() + >>> accounts = get_accounts() + +Create party:: + + >>> supplier = Party(name="Supplier") + >>> supplier.save() + +Create product:: + + >>> account_category = ProductCategory(name="Account Category") + >>> account_category.accounting = True + >>> account_category.account_expense = accounts['expense'] + >>> account_category.save() + + >>> template = ProductTemplate(name="Product") + >>> template.default_uom, = ProductUom.find([('name', '=', "Unit")]) + >>> template.type = 'goods' + >>> template.purchasable = True + >>> template.account_category = account_category + >>> template.save() + >>> product, = template.products + +Purchase product:: + + >>> purchase = Purchase(party=supplier) + >>> line = purchase.lines.new() + >>> line.product = product + >>> line.quantity = 1 + >>> line.unit_price = Decimal('10.0000') + >>> purchase.click('quote') + >>> purchase.click('confirm') + >>> purchase.state + 'processing' + >>> purchase.shipment_state + 'waiting' + >>> purchase.invoice_state + 'pending' + +Cancel stock move and invoice:: + + >>> move, = purchase.moves + >>> move.click('cancel') + >>> move.state + 'cancelled' + + >>> invoice, = purchase.invoices + >>> invoice.click('cancel') + >>> invoice.state + 'cancelled' + + >>> purchase.reload() + >>> purchase.state + 'processing' + >>> purchase.shipment_state + 'exception' + >>> purchase.invoice_state + 'exception' + +Ignore exceptions:: + + >>> invoice_handle_exception = purchase.click('handle_invoice_exception') + >>> invoice_handle_exception.form.recreate_invoices.clear() + >>> invoice_handle_exception.execute('handle') + + >>> purchase.invoice_state + 'none' + + >>> shipment_handle_exception = purchase.click('handle_shipment_exception') + >>> shipment_handle_exception.form.recreate_moves.clear() + >>> shipment_handle_exception.execute('handle') + + >>> purchase.shipment_state + 'none' + + >>> purchase.state + 'done' diff --git a/modules/sale/sale.py b/modules/sale/sale.py index 7feb939581..2a6ce1a035 100644 --- a/modules/sale/sale.py +++ b/modules/sale/sale.py @@ -961,12 +961,16 @@ class Sale( def is_done(self): return ((self.invoice_state == 'paid' or (self.invoice_state == 'none' - and all(not l.quantity - for l in self.lines if l.type == 'line'))) + and all( + l.invoice_progress >= 1 + for l in self.lines + if l.invoice_progress is not None))) and (self.shipment_state == 'sent' or (self.shipment_state == 'none' - and all(l.product.type == 'service' - for l in self.lines if l.product)))) + and all( + l.moves_progress >= 1 + for l in self.lines + if l.moves_progress is not None)))) @classmethod def delete(cls, sales): diff --git a/modules/sale/tests/scenario_sale_line_cancelled.rst b/modules/sale/tests/scenario_sale_line_cancelled.rst new file mode 100644 index 0000000000..380e2ff3aa --- /dev/null +++ b/modules/sale/tests/scenario_sale_line_cancelled.rst @@ -0,0 +1,107 @@ +============================ +Sale Line Cancelled Scenario +============================ + +Imports:: + + >>> from decimal import Decimal + + >>> from proteus import Model + >>> from trytond.tests.tools import activate_modules + >>> from trytond.modules.company.tests.tools import create_company + >>> from trytond.modules.account.tests.tools import ( + ... create_chart, get_accounts) + +Activate modules:: + + >>> config = activate_modules('sale') + + >>> Party = Model.get('party.party') + >>> ProductCategory = Model.get('product.category') + >>> ProductTemplate = Model.get('product.template') + >>> ProductUom = Model.get('product.uom') + >>> Sale = Model.get('sale.sale') + +Create company:: + + >>> _ = create_company() + +Create chart of accounts:: + + >>> _ = create_chart() + >>> accounts = get_accounts() + +Create party:: + + >>> customer = Party(name="Customer") + >>> customer.save() + +Create product:: + + >>> account_category = ProductCategory(name="Account Category") + >>> account_category.accounting = True + >>> account_category.account_revenue = accounts['revenue'] + >>> account_category.save() + + >>> template = ProductTemplate(name="Product") + >>> template.default_uom, = ProductUom.find([('name', '=', "Unit")]) + >>> template.type = 'goods' + >>> template.salable = True + >>> template.list_price = Decimal('10.0000') + >>> template.account_category = account_category + >>> template.save() + >>> product, = template.products + +Sale product:: + + >>> sale = Sale(party=customer) + >>> line = sale.lines.new() + >>> line.product = product + >>> line.quantity = 1 + >>> sale.click('quote') + >>> sale.click('confirm') + >>> sale.state + 'processing' + >>> sale.shipment_state + 'waiting' + >>> sale.invoice_state + 'pending' + +Cancel shipment and invoice:: + + >>> shipment, = sale.shipments + >>> shipment.click('cancel') + >>> shipment.state + 'cancelled' + + >>> invoice, = sale.invoices + >>> invoice.click('cancel') + >>> invoice.state + 'cancelled' + + >>> sale.reload() + >>> sale.state + 'processing' + >>> sale.shipment_state + 'exception' + >>> sale.invoice_state + 'exception' + +Ignore exceptions:: + + >>> invoice_handle_exception = sale.click('handle_invoice_exception') + >>> invoice_handle_exception.form.recreate_invoices.clear() + >>> invoice_handle_exception.execute('handle') + + >>> sale.invoice_state + 'none' + + >>> shipment_handle_exception = sale.click('handle_shipment_exception') + >>> shipment_handle_exception.form.recreate_moves.clear() + >>> shipment_handle_exception.execute('handle') + + >>> sale.shipment_state + 'none' + + >>> sale.state + 'done'