This commit is contained in:
Raimon Esteve 2022-10-26 14:04:34 +02:00
parent 16229bd9cd
commit 5a7a7c52be
12 changed files with 194 additions and 66 deletions

View File

@ -27,6 +27,8 @@ def register():
maquila.ContractProductPercentage, maquila.ContractProductPercentage,
maquila.ProductYear, maquila.ProductYear,
maquila.Maquila, maquila.Maquila,
maquila.MaquilaProductYearContractCrop,
maquila.MaquilaContractCrop,
party.Party, party.Party,
plot.Enclosure, plot.Enclosure,
plot.Crop, plot.Crop,

View File

@ -217,6 +217,17 @@ class Contract(sequence_ordered(), Workflow, ModelSQL, ModelView):
default.setdefault('maquilas', None) default.setdefault('maquilas', None)
return super(Contract, cls).copy(contracts, default=default) return super(Contract, cls).copy(contracts, default=default)
@classmethod
def delete(cls, contracts):
# Cancel before delete
cls.cancel(contracts)
for contract in contracts:
if contract.state != 'cancelled':
raise AccessError(
gettext('agronomics.msg_contract_delete_cancel',
contract=contract.rec_name))
super(Contract, cls).delete(contracts)
@fields.depends('product') @fields.depends('product')
def on_change_with_product_uom_category(self, name=None): def on_change_with_product_uom_category(self, name=None):
if self.product: if self.product:
@ -310,8 +321,8 @@ class Contract(sequence_ordered(), Workflow, ModelSQL, ModelView):
key = (self.party, crop.crop, ppercentatge.product) key = (self.party, crop.crop, ppercentatge.product)
if key in product_years: if key in product_years:
product_year = product_years.get(key) product_year = product_years.get(key)
crop.product_year = product_year product_year.contract_crops += (crop,)
crop.save() product_year.save()
new_product_years.append(product_year) new_product_years.append(product_year)
else: else:
product_year = MaquilaProductYear() product_year = MaquilaProductYear()
@ -320,9 +331,8 @@ class Contract(sequence_ordered(), Workflow, ModelSQL, ModelView):
product_year.crop = crop.crop product_year.crop = crop.crop
product_year.product = ppercentatge.product product_year.product = ppercentatge.product
product_year.unit = ppercentatge.product.default_uom product_year.unit = ppercentatge.product.default_uom
product_year.contract_crops = (crop,)
product_year.save() product_year.save()
crop.product_year = product_year
crop.save()
new_product_years.append(product_year) new_product_years.append(product_year)
return new_product_years return new_product_years
@ -336,8 +346,7 @@ class Contract(sequence_ordered(), Workflow, ModelSQL, ModelView):
products = set() products = set()
for crop in self.product_crops: for crop in self.product_crops:
crops.add(crop.crop) crops.add(crop.crop)
for ppercentatge in self.product_percentages: products.add(self.product)
products.add(ppercentatge.product)
records = Maquila.search([ records = Maquila.search([
('party', '=', self.party), ('party', '=', self.party),
@ -348,26 +357,24 @@ class Contract(sequence_ordered(), Workflow, ModelSQL, ModelView):
new_maquilas = [] new_maquilas = []
for crop in self.product_crops: for crop in self.product_crops:
for ppercentatge in self.product_percentages: key = (self.party, self.product, crop.crop, self.table)
key = (self.party, ppercentatge.product, crop.crop, self.table) if key in maquilas:
if key in maquilas: maquila = maquilas.get(key)
maquila = maquilas.get(key) maquila.contract_crops += (crop,)
crop.maquila = maquila maquila.save()
crop.save() new_maquilas.append(maquila)
new_maquilas.append(maquila) else:
else: maquila = Maquila(**default_values)
maquila = Maquila(**default_values) maquila.company = self.company
maquila.company = self.company maquila.party = self.party
maquila.party = self.party maquila.crop = crop.crop
maquila.crop = crop.crop maquila.party = self.party
maquila.party = self.party maquila.product = self.product
maquila.product = ppercentatge.product maquila.unit = self.product.default_uom
maquila.unit = ppercentatge.product.default_uom maquila.table = self.table
maquila.table = self.table maquila.contract_crops = (crop,)
maquila.save() maquila.save()
crop.maquila = maquila new_maquilas.append(maquila)
crop.save()
new_maquilas.append(maquila)
return new_maquilas return new_maquilas
@ -382,9 +389,11 @@ class ContractCrop(ModelSQL, ModelView):
depends=['currency_digits'], required=True) depends=['currency_digits'], required=True)
currency_digits = fields.Function(fields.Integer('Currency Digits'), currency_digits = fields.Function(fields.Integer('Currency Digits'),
'on_change_with_currency_digits') 'on_change_with_currency_digits')
product_year = fields.Many2One('agronomics.maquila.product_year', product_years = fields.Many2Many(
"Product Year", readonly=True) 'agronomics.maquila.product_year-agronomics.maquila.contract.crop', 'contract_crop', 'product_year', "Product Years")
maquila = fields.Many2One('agronomics.maquila', "Maquila", readonly=True) maquilas = fields.Many2Many(
'agronomics.maquila-agronomics.maquila.contract.crop',
'contract_crop', 'maquila', "Maquila", readonly=True)
def on_change_with_currency_digits(self, name=None): def on_change_with_currency_digits(self, name=None):
Company = Pool().get('company.company') Company = Pool().get('company.company')
@ -421,6 +430,9 @@ class ProductYear(ModelSQL, ModelView):
quantity = fields.Function(fields.Float("Quantity", quantity = fields.Function(fields.Float("Quantity",
digits=(16, Eval('unit_digits', 2)), digits=(16, Eval('unit_digits', 2)),
depends=['unit_digits']), 'get_quantity') depends=['unit_digits']), 'get_quantity')
delivered_quantity = fields.Function(fields.Float("Delivered Quantity",
digits=(16, Eval('unit_digits', 2)),
depends=['unit_digits']), 'get_delivered_quantity')
unit = fields.Many2One('product.uom', "Unit", required=True, readonly=True, unit = fields.Many2One('product.uom', "Unit", required=True, readonly=True,
ondelete='RESTRICT', domain=[ ondelete='RESTRICT', domain=[
If(Bool(Eval('product_uom_category')), If(Bool(Eval('product_uom_category')),
@ -433,8 +445,9 @@ class ProductYear(ModelSQL, ModelView):
product_uom_category = fields.Function( product_uom_category = fields.Function(
fields.Many2One('product.uom.category', "Product Uom Category"), fields.Many2One('product.uom.category', "Product Uom Category"),
'on_change_with_product_uom_category') 'on_change_with_product_uom_category')
contract_crops = fields.One2Many('agronomics.maquila.contract.crop', contract_crops = fields.Many2Many(
'product_year', "Crops", readonly=True) 'agronomics.maquila.product_year-agronomics.maquila.contract.crop',
'product_year', 'contract_crop', "Contract Crops", readonly=True)
contracts = fields.Function(fields.One2Many('agronomics.maquila.contract', contracts = fields.Function(fields.One2Many('agronomics.maquila.contract',
None, "Contracts"), 'get_contracts', searcher='search_contracts') None, "Contracts"), 'get_contracts', searcher='search_contracts')
@ -445,6 +458,25 @@ class ProductYear(ModelSQL, ModelView):
('id', 'DESC'), ('id', 'DESC'),
] ]
def get_rec_name(self, name):
items = []
items.append(self.party.rec_name)
items.append('[%s]' % self.crop.rec_name)
return ' '.join(items)
@classmethod
def search_rec_name(cls, name, clause):
_, operator, value = clause
if operator.startswith('!') or operator.startswith('not '):
bool_op = 'AND'
else:
bool_op = 'OR'
domain = [bool_op,
('party', operator, value),
('crop', operator, value),
]
return domain
@fields.depends('product') @fields.depends('product')
def on_change_with_product_uom_category(self, name=None): def on_change_with_product_uom_category(self, name=None):
if self.product: if self.product:
@ -478,6 +510,29 @@ class ProductYear(ModelSQL, ModelView):
res[product_year.id] = _sum res[product_year.id] = _sum
return res return res
@classmethod
def get_delivered_quantity(cls, product_years, name):
pool = Pool()
SaleLine = pool.get('sale.line')
Uom = pool.get('product.uom')
res = dict((x.id, 0) for x in product_years)
for product_year in product_years:
lines = SaleLine.search([
('maquila', '=', product_year),
('product', '=', product_year.product),
('sale.state', 'not in', ['cancelled', 'draft', 'quotation']),
])
_sum = 0
for line in lines:
for move in line.moves:
if not move.state == 'done':
continue
_sum += Uom.compute_qty(move.uom, move.quantity, product_year.unit, False)
res[product_year.id] = _sum
return res
@classmethod @classmethod
def get_contracts(cls, product_years, name): def get_contracts(cls, product_years, name):
res = dict((x.id, None) for x in product_years) res = dict((x.id, None) for x in product_years)
@ -505,6 +560,9 @@ class Maquila(ModelSQL, ModelView):
quantity = fields.Function(fields.Float("Quantity", quantity = fields.Function(fields.Float("Quantity",
digits=(16, Eval('unit_digits', 2)), digits=(16, Eval('unit_digits', 2)),
depends=['unit_digits']), 'get_quantity') depends=['unit_digits']), 'get_quantity')
pending_quantity = fields.Function(fields.Float("Pending Quantity",
digits=(16, Eval('unit_digits', 2)),
depends=['unit_digits']), 'get_pending_quantity')
product = fields.Many2One('product.product', "Product", required=True, product = fields.Many2One('product.product', "Product", required=True,
readonly=True, readonly=True,
context={ context={
@ -528,8 +586,9 @@ class Maquila(ModelSQL, ModelView):
product_year = fields.Many2One('agronomics.maquila.product_year', product_year = fields.Many2One('agronomics.maquila.product_year',
"Product Year", readonly=True) "Product Year", readonly=True)
table = fields.Boolean("Table", readonly=True) table = fields.Boolean("Table", readonly=True)
contract_crops = fields.One2Many('agronomics.maquila.contract.crop', 'maquila', contract_crops = fields.Many2Many(
"Crops", readonly=True) 'agronomics.maquila-agronomics.maquila.contract.crop',
'maquila', 'contract_crop', "Contract Crops", readonly=True)
contracts = fields.Function(fields.One2Many('agronomics.maquila.contract', contracts = fields.Function(fields.One2Many('agronomics.maquila.contract',
None, "Contracts"), 'get_contracts', searcher='search_contracts') None, "Contracts"), 'get_contracts', searcher='search_contracts')
@ -544,6 +603,25 @@ class Maquila(ModelSQL, ModelView):
('id', 'DESC'), ('id', 'DESC'),
] ]
def get_rec_name(self, name):
items = []
items.append(self.party.rec_name)
items.append('[%s]' % self.crop.rec_name)
return ' '.join(items)
@classmethod
def search_rec_name(cls, name, clause):
_, operator, value = clause
if operator.startswith('!') or operator.startswith('not '):
bool_op = 'AND'
else:
bool_op = 'OR'
domain = [bool_op,
('party', operator, value),
('crop', operator, value),
]
return domain
@fields.depends('product') @fields.depends('product')
def on_change_with_product_uom_category(self, name=None): def on_change_with_product_uom_category(self, name=None):
if self.product: if self.product:
@ -556,25 +634,66 @@ class Maquila(ModelSQL, ModelView):
return 2 return 2
@classmethod @classmethod
def get_quantity(cls, product_years, name): def get_quantity(cls, maquilas, name):
res = dict((x.id, 0) for x in product_years) res = dict((x.id, 0) for x in maquilas)
for product_year in product_years: for maquila in maquilas:
_sum = 0 _sum = 0
for crop in product_year.contract_crops: for crop in maquila.contract_crops:
for ppercentatge in crop.contract.product_percentages: if crop.contract.product == maquila.product:
if ppercentatge.product == product_year.product: _sum += crop.quantity
_sum += crop.quantity * ppercentatge.percentatge res[maquila.id] = _sum
res[product_year.id] = _sum
return res return res
@classmethod @classmethod
def get_contracts(cls, product_years, name): def get_pending_quantity(cls, maquilas, name):
res = dict((x.id, None) for x in product_years) pool = Pool()
for product_year in product_years: Weighing = pool.get('agronomics.weighing')
contracts = [crop.contract.id for crop in product_year.contract_crops] Uom = pool.get('product.uom')
res[product_year.id] = contracts
res = dict((x.id, 0) for x in maquilas)
for maquila in maquilas:
weighings = Weighing.search([
('maquila', '=', maquila),
('product', '=', maquila.product),
('state', '=', 'done'),
])
_sum = 0
for weighing in weighings:
move = weighing.inventory_move
if move:
_sum += Uom.compute_qty(move.uom, move.quantity, maquila.unit, False)
res[maquila.id] = maquila.quantity - _sum
return res
@classmethod
def get_contracts(cls, maquilas, name):
res = dict((x.id, None) for x in maquilas)
for maquila in maquilas:
contracts = [crop.contract.id for crop in maquila.contract_crops]
res[maquila.id] = contracts
return res return res
@classmethod @classmethod
def search_contracts(cls, name, clause): def search_contracts(cls, name, clause):
return [('contract_crops.contract',) + tuple(clause[1:])] return [('contract_crops.contract',) + tuple(clause[1:])]
class MaquilaProductYearContractCrop(ModelSQL):
'Party - Category'
__name__ = 'agronomics.maquila.product_year-agronomics.maquila.contract.crop'
_table = 'agronomics_maquila_product_year_contract_crop_rel'
product_year = fields.Many2One('agronomics.maquila.product_year', "Product Year", ondelete='CASCADE',
required=True, select=True)
contract_crop = fields.Many2One('agronomics.maquila.contract.crop', "Contract Crop",
ondelete='CASCADE', required=True, select=True)
class MaquilaContractCrop(ModelSQL):
'Party - Category'
__name__ = 'agronomics.maquila-agronomics.maquila.contract.crop'
_table = 'agronomics_maquila_contract_crop_rel'
maquila = fields.Many2One('agronomics.maquila', "Maquila", ondelete='CASCADE',
required=True, select=True)
contract_crop = fields.Many2One('agronomics.maquila.contract.crop', "Contract Crop",
ondelete='CASCADE', required=True, select=True)

View File

@ -51,5 +51,8 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.message" id="msg_maquila_contract_quantity"> <record model="ir.message" id="msg_maquila_contract_quantity">
<field name="text">Total quantity is different from the quantity from the contract "%(contract)s".</field> <field name="text">Total quantity is different from the quantity from the contract "%(contract)s".</field>
</record> </record>
<record model="ir.message" id="msg_contract_delete_cancel">
<field name="text">To delete contract "%(contract)s" you must cancel it.</field>
</record>
</data> </data>
</tryton> </tryton>

13
sale.py
View File

@ -89,14 +89,11 @@ class Sale(metaclass=PoolMeta):
class SaleLine(metaclass=PoolMeta): class SaleLine(metaclass=PoolMeta):
__name__ = 'sale.line' __name__ = 'sale.line'
maquila_product = fields.Many2One('product.product', "Maquila Product", maquila = fields.Many2One('agronomics.maquila.product_year', "Maquila",
ondelete='RESTRICT', domain=[
states={ ('product', '=', Eval('product')),
'invisible': ~Bool(Eval('_parent_sale', {}).get('is_maquila')), ('party', '=', Eval('_parent_sale', {}).get('party')),
'required': Bool(Eval('_parent_sale', {}).get('is_maquila')), ],
'readonly': Eval('sale_state') != 'draft',
}, depends=['sale_state'])
maquila = fields.Many2One('agronomics.maquila', "Maquila",
states={ states={
'invisible': ~Bool(Eval('_parent_sale', {}).get('is_maquila')), 'invisible': ~Bool(Eval('_parent_sale', {}).get('is_maquila')),
'required': Bool(Eval('_parent_sale', {}).get('is_maquila')), 'required': Bool(Eval('_parent_sale', {}).get('is_maquila')),

View File

@ -8,6 +8,7 @@
<field name="quantity"/> <field name="quantity"/>
<label name="penality"/> <label name="penality"/>
<field name="penality"/> <field name="penality"/>
<label name="maquila"/> <newline/>
<field name="maquila"/> <field name="product_years" colspan="6"/>
<field name="maquilas" colspan="6"/>
</form> </form>

View File

@ -7,4 +7,5 @@
<field name="table"/> <field name="table"/>
<field name="state"/> <field name="state"/>
<field name="company"/> <field name="company"/>
<field name="reference"/>
</tree> </tree>

View File

@ -2,6 +2,8 @@
<form> <form>
<label name="party"/> <label name="party"/>
<field name="party"/> <field name="party"/>
<label name="company"/>
<field name="company"/>
<label name="crop"/> <label name="crop"/>
<field name="crop"/> <field name="crop"/>
<label name="table"/> <label name="table"/>
@ -12,8 +14,8 @@
<field name="unit"/> <field name="unit"/>
<label name="quantity"/> <label name="quantity"/>
<field name="quantity"/> <field name="quantity"/>
<label name="company"/> <label name="pending_quantity"/>
<field name="company"/> <field name="pending_quantity"/>
<newline/> <newline/>
<field name="contract_crops" colspan="6"/> <field name="contract_crops" colspan="6"/>
<field name="contracts" colspan="6"/> <field name="contracts" colspan="6"/>

View File

@ -4,6 +4,7 @@
<field name="crop"/> <field name="crop"/>
<field name="table"/> <field name="table"/>
<field name="product"/> <field name="product"/>
<field name="quantity"/>
<field name="unit"/> <field name="unit"/>
<field name="company"/> <field name="company"/>
<field name="contracts" tree_invisible="1"/> <field name="contracts" tree_invisible="1"/>

View File

@ -2,12 +2,16 @@
<form> <form>
<label name="party"/> <label name="party"/>
<field name="party"/> <field name="party"/>
<label name="company"/>
<field name="company"/>
<label name="crop"/> <label name="crop"/>
<field name="crop"/> <field name="crop"/>
<label name="product"/> <label name="product"/>
<field name="product"/> <field name="product"/>
<label name="quantity"/> <label name="quantity"/>
<field name="quantity"/> <field name="quantity"/>
<label name="delivered_quantity"/>
<field name="delivered_quantity"/>
<label name="unit"/> <label name="unit"/>
<field name="unit"/> <field name="unit"/>
<newline/> <newline/>

View File

@ -3,8 +3,6 @@
this repository contains the full copyright notices and license terms. --> this repository contains the full copyright notices and license terms. -->
<data> <data>
<xpath expr="/form/notebook/page[@id='general']/field[@name='amount']" position="after"> <xpath expr="/form/notebook/page[@id='general']/field[@name='amount']" position="after">
<label name="maquila_product"/>
<field name="maquila_product"/>
<label name="maquila"/> <label name="maquila"/>
<field name="maquila"/> <field name="maquila"/>
</xpath> </xpath>

View File

@ -3,7 +3,6 @@
this repository contains the full copyright notices and license terms. --> this repository contains the full copyright notices and license terms. -->
<data> <data>
<xpath expr="/tree/field[@name='amount']" position="after"> <xpath expr="/tree/field[@name='amount']" position="after">
<field name="maquila_product"/>
<field name="maquila"/> <field name="maquila"/>
</xpath> </xpath>
</data> </data>

View File

@ -126,18 +126,19 @@ class Weighing(Workflow, ModelSQL, ModelView):
inventory_move = fields.Many2One('stock.move', "Inventory Move", inventory_move = fields.Many2One('stock.move', "Inventory Move",
readonly=True) readonly=True)
is_maquila = fields.Boolean("Is Maquila", states={ is_maquila = fields.Boolean("Is Maquila", states={
'readonly': Eval('state').in_(READONLY2), 'readonly': Eval('state').in_(READONLY),
}, depends=['state']) }, depends=['state'])
# TODO weighing table is readonly when is draft # TODO weighing table is readonly when is draft
maquila = fields.Many2One('agronomics.maquila', "Maquila", maquila = fields.Many2One('agronomics.maquila', "Maquila",
domain=[ domain=[
('table', '=', Bool(Eval('table', False))), ('table', '=', Bool(Eval('table', False))),
('product', '=', Eval('product')),
], ],
states={ states={
'readonly': Eval('state').in_(READONLY2), 'readonly': Eval('state').in_(['in_analysis', 'done', 'cancelled']),
'invisible': ~Eval('is_maquila', False), 'invisible': ~Eval('is_maquila', False),
'required': Eval('is_maquila', False), 'required': (Bool(Eval('is_maquila', False)) & (Eval('state') == 'in_analysis')),
}, depends=['is_maquila', 'table', 'state']) }, depends=['is_maquila', 'table', 'product', 'state'])
@classmethod @classmethod
def __setup__(cls): def __setup__(cls):
@ -463,7 +464,7 @@ class Weighing(Workflow, ModelSQL, ModelView):
InvoiceLine = pool.get('account.invoice.line') InvoiceLine = pool.get('account.invoice.line')
Product = pool.get('product.product') Product = pool.get('product.product')
Company = pool.get('company.company') Company = pool.get('company.company')
Maquila = pool.get('agronomics.maquila')
ContractProductPriceListTypePriceList = pool.get( ContractProductPriceListTypePriceList = pool.get(
'agronomics.contract-product.price_list.type-product.price_list') 'agronomics.contract-product.price_list.type-product.price_list')
WeighingInvoiceLine = pool.get( WeighingInvoiceLine = pool.get(