diff --git a/modules/purchase/CHANGELOG b/modules/purchase/CHANGELOG index 177d0a5512..3316b68938 100644 --- a/modules/purchase/CHANGELOG +++ b/modules/purchase/CHANGELOG @@ -1,3 +1,4 @@ +* Require unit price only for confirmed purchase * Do not invoice non purchase line * Rename UOM to Unit for product supplier * Use price from last purchase as product price diff --git a/modules/purchase/purchase.fodt b/modules/purchase/purchase.fodt index 6239611cd3..d0cf2e6dbe 100644 --- a/modules/purchase/purchase.fodt +++ b/modules/purchase/purchase.fodt @@ -1,128 +1,142 @@ - - LibreOffice/6.4.6.2$Linux_X86_64 LibreOffice_project/40$Build-22008-06-07T15:28:222009-01-10T16:03:321PT0S + + LibreOffice/7.4.6.2$Linux_X86_64 LibreOffice_project/40$Build-22008-06-07T15:28:222009-01-10T16:03:321PT0S - 21167 + 58208 0 - 26301 - 24026 + 25269 + 22994 true false view2 - 4355 - 33754 + 21310 + 74634 0 - 21167 - 26300 - 45191 + 58208 + 25268 + 81201 0 0 false 100 false + false + false false false - true - true - true - 0 - true - true - - false - false - false - false - false - false false - false + false + true + true + true + true + true + false + 0 + false + false + false + false + true + true + false + false + false + false + false + true true true - true false + false + false false - false - false false false false - false - false - true - false - true - true - 947783 - false - - false - true - false - false - false - true + false + true false - false - false + false true - 3903666 - + false + false + false + true + 0 + 1 + true + false + + high-resolution + false + + + false + false true + false + false + true + true + false + true + + true + 3944332 + + true + false + true + true + 0 + + false + false + false + false + false + true + 0 + false + false + false + false + true + false + false + false + + false false true - false - false - true - true - false - true - false - false - false - 0 - false - true - high-resolution - false - false - false - false - false - false - true - true - true - - true - false - false - true - false - false - false - - false - false - false - 1 - true - false false - 0 + false + false false false - - - false + false + false + false + false + 947783 + false + false + false + false + false + false + true + true + false @@ -131,26 +145,26 @@ - - - - - - + + + + + + - + - + - + @@ -162,18 +176,18 @@ - - + + - + - + @@ -228,51 +242,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -402,6 +416,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -418,104 +460,107 @@ - - - - - + - - + + + + + + - - + + + + + - - - - + - - + + - + + + + - + - + + + + + - + - + - - - - - - - - - - + + - - + + - + - + + + + + - - - - + - - - - - + + + + + + + + @@ -537,7 +582,7 @@ - + @@ -547,16 +592,19 @@ + + + - + <if test="company and company.header"> <for each="line in company.header.split('\n')"> <line> </for> </if> - <company.rec_name if company else ''> + <company.rec_name if company else ''> <if test="company and company.footer"> @@ -577,31 +625,31 @@ - <for each="purchase in records"> - - <replace text:p="set_lang(purchase.party.lang)"> - <replace text:p="purchase.set_lang(purchase.party.lang)"> - <for each="line in purchase.report_address.splitlines()"> - <line> - </for> - <if test="purchase.party.tax_identifier"> - <purchase.party.tax_identifier.type_string>: <purchase.party.tax_identifier.code> - </if> + <for each="purchase in records"> + + <replace text:p="set_lang(purchase.party.lang)"> + <replace text:p="purchase.set_lang(purchase.party.lang)"> + <for each="line in purchase.report_address.splitlines()"> + <line> + </for> + <if test="purchase.party.tax_identifier"> + <purchase.party.tax_identifier.type_string>: <purchase.party.tax_identifier.code> + </if> <choose test=""> - <when test="purchase.state == 'draft'"> - Draft Purchase Order - </when> - <when test="purchase.state == 'quotation'"> - Request for Quotation N°: <purchase.full_number> - </when> - <otherwise test=""> - Purchase Order N°: <purchase.full_number> - </otherwise> - </choose> + <when test="purchase.state == 'draft'"> + Draft Purchase Order + </when> + <when test="purchase.state == 'quotation'"> + Request for Quotation N°: <purchase.full_number> + </when> + <otherwise test=""> + Purchase Order N°: <purchase.full_number> + </otherwise> + </choose> - Description: <purchase.description or ''> - Reference: <purchase.reference or ''> - Customer Code: <purchase.party.get_multivalue('customer_code', company=purchase.company.id) or ''> + Description: <purchase.description or ''> + Reference: <purchase.reference or ''> + Customer Code: <purchase.party.get_multivalue('customer_code', company=purchase.company.id) or ''> Date: <format_date(purchase.purchase_date or today, purchase.party.lang)> Delivery Address: <for each="line in purchase.delivery_full_address.splitlines()"> @@ -631,7 +679,7 @@ - + <for each="line in purchase.lines"> @@ -640,7 +688,7 @@ - + <choose test=""> @@ -649,7 +697,7 @@ - + <when test="line.type == 'line'"> @@ -659,37 +707,41 @@ - <choose> - <when test="line.product_supplier"> - <line.product_supplier.rec_name> - </when> - <when test="line.product"> - <line.product.rec_name> - </when> - </choose> - <if test="line.description"> - <for each="description in line.description.split('\n')"> - <description> - </for> - </if> + <choose> + <when test="line.product_supplier"> + <line.product_supplier.rec_name> + </when> + <when test="line.product"> + <line.product.rec_name> + </when> + </choose> + <if test="line.description"> + <for each="description in line.description.split('\n')"> + <description> + </for> + </if> - - <format_number_symbol(line.quantity, purchase.party.lang, line.unit, digits=line.unit.digits) if line.unit else format_number(line.quantity, purchase.party.lang)> + + <format_number_symbol(line.quantity, purchase.party.lang, line.unit, digits=line.unit.digits) if line.unit else format_number(line.quantity, purchase.party.lang)> - - <format_currency(line.unit_price, purchase.party.lang, purchase.currency, digits=line.__class__.unit_price.digits[1])> + + <if test="line.unit_price is not None"> + <format_currency(line.unit_price, purchase.party.lang, purchase.currency, digits=line.__class__.unit_price.digits[1])> + </if> - - <for each="tax in line.taxes"> - <tax.description> - </for> + + <for each="tax in line.taxes"> + <tax.description> + </for> - - <format_currency(line.amount, purchase.party.lang, purchase.currency)> + + <if test="line.amount is not None"> + <format_currency(line.amount, purchase.party.lang, purchase.currency)> + </if> - + </when> @@ -698,7 +750,7 @@ - + <when test="line.type == 'subtotal'"> @@ -709,18 +761,18 @@ <for each="description in (line.description or '').split('\n')"> - <description> - </for> + <description> + </for> - - <format_currency(line.amount, purchase.party.lang, purchase.currency)> + + <format_currency(line.amount, purchase.party.lang, purchase.currency)> - + </when> @@ -729,7 +781,7 @@ - + <when test="line.type == 'title'"> @@ -749,7 +801,7 @@ - + </when> @@ -758,7 +810,7 @@ - + <otherwise test=""> @@ -767,10 +819,10 @@ - - <for each="description in (line.description or '').split('\n')"> - <description> - </for> + + <for each="description in (line.description or '').split('\n')"> + <description> + </for> @@ -778,7 +830,7 @@ - + </otherwise> @@ -787,7 +839,7 @@ - + </choose> @@ -796,7 +848,7 @@ - + </for> @@ -820,26 +872,26 @@ - Total (excl. taxes): + Total (excl. taxes): - <format_currency(purchase.untaxed_amount, purchase.party.lang, purchase.currency)> + <format_currency(purchase.untaxed_amount, purchase.party.lang, purchase.currency)> - Taxes: + Taxes: - - <format_currency(purchase.tax_amount, purchase.party.lang, purchase.currency)> + + <format_currency(purchase.tax_amount, purchase.party.lang, purchase.currency)> - Total: + Total: - - <format_currency(purchase.total_amount, purchase.party.lang, purchase.currency)> + + <format_currency(purchase.total_amount, purchase.party.lang, purchase.currency)> @@ -853,4 +905,4 @@ </for> - + \ No newline at end of file diff --git a/modules/purchase/purchase.py b/modules/purchase/purchase.py index 4c88fa82f2..90926e4321 100644 --- a/modules/purchase/purchase.py +++ b/modules/purchase/purchase.py @@ -528,7 +528,8 @@ class Purchase( else: untaxed_amount[purchase.id] = sum( (line.amount for line in purchase.lines - if line.type == 'line'), Decimal(0)) + if line.type == 'line' and line.amount is not None), + Decimal(0)) if compute_taxes: tax_amount[purchase.id] = purchase.get_tax_amount() total_amount[purchase.id] = ( @@ -876,9 +877,16 @@ class Purchase( @Workflow.transition('confirmed') @set_employee('confirmed_by') def confirm(cls, purchases): + pool = Pool() + Line = pool.get('purchase.line') transaction = Transaction() context = transaction.context cls.set_purchase_date(purchases) + + cls.write(purchases, {'state': 'confirmed'}) + lines = list(sum((p.lines for p in purchases), ())) + Line._validate(lines, ['unit_price']) + cls.store_cache(purchases) for process_after, sub_purchases in groupby( purchases, lambda p: p.process_after): @@ -1158,7 +1166,10 @@ class Line(sequence_ordered(), ModelSQL, ModelView): ], states={ 'invisible': Eval('type') != 'line', - 'required': Eval('type') == 'line', + 'required': ( + (Eval('type') == 'line') + & Eval('purchase_state').in_( + ['confirmed', 'processing', 'done'])), 'readonly': Eval('purchase_state') != 'draft', }) amount = fields.Function(Monetary( @@ -1475,14 +1486,14 @@ class Line(sequence_ordered(), ModelSQL, ModelView): 'type', 'quantity', 'unit_price', 'purchase', '_parent_purchase.currency') def on_change_with_amount(self): - if self.type == 'line': + if (self.type == 'line' + and self.quantity is not None + and self.unit_price is not None): currency = self.purchase.currency if self.purchase else None - amount = Decimal(str(self.quantity or '0.0')) * \ - (self.unit_price or Decimal('0.0')) + amount = Decimal(str(self.quantity)) * self.unit_price if currency: return currency.round(amount) return amount - return Decimal('0.0') def get_amount(self, name): if self.type == 'line': @@ -1498,7 +1509,6 @@ class Line(sequence_ordered(), ModelSQL, ModelView): break amount = Decimal('0.0') return amount - return Decimal('0.0') @fields.depends('purchase', '_parent_purchase.warehouse') def on_change_with_warehouse(self, name=None):