Added specific purchase apply method.

This commit refs #22792
This commit is contained in:
Sergio Morillo 2022-05-16 12:49:46 +02:00
parent 7c1e37e325
commit 6cfb63fb3d
8 changed files with 186 additions and 47 deletions

View File

@ -1,11 +1,13 @@
# The COPYRIGHT file at the top level of this repository contains
# the full copyright notices and license terms.
from trytond.pool import Pool
from .sale_cost import SaleCost
from . import purchase
from . import sale_cost
def register():
Pool.register(
SaleCost,
sale_cost.SaleCost,
sale_cost.CostType,
purchase.Line,
module='sale_cost_apply_purchase', type_='model')

View File

@ -5,3 +5,11 @@ msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:sale.cost,purchase:"
msgid "Purchase"
msgstr "Compra"
msgctxt "field:sale.cost,purchase_lines:"
msgid "Purchase lines"
msgstr "Líneas de compra"
msgctxt "selection:sale.cost.type,apply_method:"
msgid "Purchase"
msgstr "Compra"

13
purchase.py Normal file
View File

@ -0,0 +1,13 @@
# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
from trytond.pool import PoolMeta
class Line(metaclass=PoolMeta):
__name__ = 'purchase.line'
@classmethod
def _get_origin(cls):
result = super()._get_origin()
result.append('sale.cost')
return result

View File

@ -1,16 +1,29 @@
# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
from decimal import Decimal
from trytond.pool import PoolMeta, Pool
from trytond.model import fields
from trytond.pyson import Eval, Not, Bool, Or
from trytond.transaction import Transaction
from trytond.exceptions import UserError
from trytond.i18n import gettext
from sql.operators import Concat
from functools import partial
from itertools import groupby
class SaleCost(metaclass=PoolMeta):
__name__ = 'sale.cost'
purchase = fields.Many2One('purchase.purchase', 'Purchase', readonly=True,
purchase = fields.Function(
fields.Many2One('purchase.purchase', 'Purchase', readonly=True,
states={
'invisible': Eval('apply_method', '') != 'invoice_in'
'invisible': Eval('apply_method', '') != 'purchase'
}, depends=['apply_method']), 'get_purchase')
purchase_lines = fields.One2Many('purchase.line', 'origin',
'Purchase lines',
states={
'invisible': Eval('apply_method', '') != 'purchase'
}, depends=['apply_method'])
@classmethod
@ -26,67 +39,117 @@ class SaleCost(metaclass=PoolMeta):
invisible_condition,
Not(Bool(Eval('purchase'))))
cls._buttons['unapply']['depends'].append('purchase')
cls.apply_method.selection.append(('purchase', 'Purchase'))
cls.invoice_party.states['invisible'] &= (
Eval('apply_method') != 'purchase')
@classmethod
def create_invoice_lines(cls, apply_method, costs):
def __register__(cls, module_name):
table = cls.__table_handler__(module_name)
Purchase_lines = Pool().get('purchase.line')
cursor = Transaction().connection.cursor()
sql_table = cls.__table__()
purchase_line = Purchase_lines.__table__()
purchase_exists = table.column_exist('purchase')
super(SaleCost, cls).__register__(module_name)
if purchase_exists:
cursor.execute(*purchase_line.join(sql_table,
condition=purchase_line.purchase == sql_table.purchase
).select(
purchase_line.id,
sql_table.id,
where=(purchase_line.type == 'line'))
)
for pline_id, cost_id in cursor.fetchall():
cursor.execute(*purchase_line.update(
columns=[purchase_line.origin],
values=[Concat(cls.__name__ + ',', cost_id)],
where=purchase_line.id == pline_id
))
table.drop_column('purchase')
def get_purchase(self, name=None):
if self.purchase_lines:
return self.purchase_lines[0].purchase.id
@classmethod
def _apply_method(cls, apply_method, costs):
Purchase = Pool().get('purchase.purchase')
if apply_method != 'invoice_in':
return super().create_invoice_lines(apply_method, costs)
if apply_method != 'purchase':
return super()._apply_method(apply_method, costs)
lines = []
for cost in costs:
lines.extend(cost._get_purchase_lines(apply_method))
if lines:
Purchase.quote(list(set([l.purchase for l in lines])))
cost_keyfunc = partial(cls._get_purchase_keygroup)
sorted_cost_lines = sorted(costs, key=cost_keyfunc)
purchases = []
for key, grouped_lines in groupby(sorted_cost_lines, key=cost_keyfunc):
purchase = Purchase(**dict(key))
purchase.on_change_party()
lines = []
group_lines = list(grouped_lines)
for cost in group_lines:
lines.append(cost._get_purchase_line(purchase))
purchase.lines = lines
purchases.append(purchase)
Purchase.save(purchases)
Purchase.quote(purchases)
return []
def _get_purchase_lines(self, apply_method):
def _get_purchase_line(self, purchase):
pool = Pool()
PurchaseLine = pool.get('purchase.line')
Purchase = pool.get('purchase.purchase')
if not self.amount or self.purchase:
return []
purchase = Purchase(
party=self.invoice_party,
company=self.document.company,
purchase_date=self.sale.sale_date)
purchase.on_change_party()
self.purchase = purchase
line = PurchaseLine()
line.purchase = purchase
line.type = 'line'
line.product = self.type_.product
line.quantity = 1
line.unit = self.type_.product.default_uom
line.on_change_product()
line.quantity = self.quantity
line.on_change_quantity()
line.unit_price = self.amount
taxes = []
for tax in line.product.supplier_taxes_used:
if self.invoice_party.supplier_tax_rule:
pattern = self._get_tax_rule_pattern()
tax_ids = self.invoice_party.supplier_tax_rule.apply(
tax, pattern)
if tax_ids:
taxes.extend(tax_ids)
continue
taxes.append(tax.id)
line.taxes = taxes
purchase.lines = [line]
self.save()
return list(purchase.lines)
digits = PurchaseLine.unit_price.digits[1]
line.unit_price = (self.amount / Decimal(str(self.quantity))
).quantize(Decimal(10) ** -Decimal(digits))
line.amount = line.on_change_with_amount()
line.origin = self
return line
@classmethod
def _get_purchase_keygroup(cls, cost):
if not cost.invoice_party:
raise UserError(gettext('document_cost_apply_invoice.'
'msg_document_cost_apply_invoice_invoice_no_party',
type_=cost.type_.rec_name,
cost=cost.document.rec_name))
return [
('company', cost.document.company),
('party', cost.invoice_party),
('purchase_date', cost.sale.sale_date)]
@classmethod
def _unapply_method(cls, apply_method, costs):
pool = Pool()
Purchase = pool.get('purchase.purchase')
if apply_method != 'invoice_in':
if apply_method != 'purchase':
super(SaleCost, cls)._unapply_method(apply_method, costs)
purchases = Purchase.search([
('id', 'in', [c.purchase.id for c in costs if c.purchase])])
if purchases:
Purchase.delete(purchases)
class CostType(metaclass=PoolMeta):
__name__ = 'sale.cost.type'
@classmethod
def __setup__(cls):
super(CostType, cls).__setup__()
cls.apply_method.selection.append(('purchase', 'Purchase'))

View File

@ -9,7 +9,8 @@ import io
from configparser import ConfigParser
MODULE2PREFIX = {
'sale_cost_apply_invoice': 'datalife'
'sale_cost_apply_invoice': 'datalife',
'purchase_origin': 'datalife'
}
@ -53,6 +54,19 @@ dependency_links = {
'trytond-sale_cost_apply_invoice@%(branch)s'
'#egg=datalife_sale_cost_apply_invoice' % {
'branch': branch,
},
'purchase_origin':
'git+https://gitlab.com/datalifeit/'
'trytond-purchase_origin@%(branch)s'
'#egg=datalife_purchase_origin' % {
'branch': branch,
},
'sale_processing2confirmed':
'git+https://gitlab.com/datalifeit/'
'trytond-sale_processing2confirmed@%(branch)s'
'#egg=nantic_sale_processing2confirmed-%(series)s' % {
'branch': branch,
'series': series
}
}
@ -69,7 +83,10 @@ for dep in info.get('depends', []):
requires.append(get_require_version('trytond'))
tests_require = [get_require_version('proteus')]
tests_require = [
get_require_version('proteus'),
get_require_version('nantic_sale_processing2confirmed'),
]
dependency_links = list(dependency_links.values())
if minor_version % 2:

View File

@ -20,7 +20,7 @@ Imports::
Install sale_cost_apply_purchase::
>>> config = activate_modules('sale_cost_apply_purchase')
>>> config = activate_modules(['sale_cost_apply_purchase', 'sale_processing2confirmed'])
Create company::
@ -165,6 +165,36 @@ Sale 2 products::
>>> sale.untaxed_amount, sale.tax_amount, sale.total_amount
(Decimal('29.00'), Decimal('2.90'), Decimal('31.90'))
Create cost type purchase::
>>> type_invoice.apply_method = 'purchase'
>>> type_invoice.product = service
>>> type_invoice.save()
Check purchase lines::
>>> SaleCost = Model.get('sale.cost')
>>> sale_cost = SaleCost()
>>> sale_cost.invoice_party = supplier
>>> sale_cost.document = sale
>>> sale_cost.type_ = type_invoice
>>> sale_cost.template = template
>>> sale_cost.save()
>>> sale_cost.click('apply')
>>> len([sale_cost.purchase])
1
>>> PurchaseLine = Model.get('purchase.line')
>>> line, = PurchaseLine.find([()])
>>> line.origin == sale_cost
True
>>> sale_cost.click('unapply')
>>> sale_cost.reload()
>>> lines = PurchaseLine.find([()])
>>> len(lines)
0
>>> sale_cost.click('delete')
Check cost applying::
>>> invoice_cost, = sale.costs
@ -180,7 +210,7 @@ Check cost applying::
True
>>> line.unit_price == invoice_cost.amount
True
>>> sale.click('quote')
>>> sale.click('unprocess')
>>> lines = PurchaseLine.find([()])
>>> len(lines)
0

View File

@ -5,5 +5,6 @@ depends:
res
sale_cost_apply_invoice
purchase
purchase_origin
xml:
sale_cost.xml
sale_cost.xml

View File

@ -6,4 +6,9 @@
<label name="purchase"/>
<field name="purchase"/>
</xpath>
<xpath expr="/form/notebook" position="inside">
<page name="purchase_lines">
<field name="purchase_lines"/>
</page>
</xpath>
</data>