from trytond.model import ModelSQL, ModelView, fields from trytond.pool import PoolMeta, Pool from trytond.exceptions import UserError from trytond.modules.purchase_trade.purchase import (TRIGGERS) from trytond.transaction import Transaction from decimal import getcontext, Decimal, ROUND_HALF_UP from sql import Table from trytond.pyson import Bool, Eval, Id, If class PartyExecution(ModelSQL,ModelView): "Party Execution" __name__ = 'party.execution' party = fields.Many2One('party.party',"Party") area = fields.Many2One('country.region',"Area") percent = fields.Numeric("% targeted") achieved_percent = fields.Function(fields.Numeric("% achieved"),'get_percent') @staticmethod def _to_decimal(value): if value is None: return Decimal('0') if isinstance(value, Decimal): return value return Decimal(str(value)) @classmethod def _round_percent(cls, value): return cls._to_decimal(value).quantize( Decimal('0.01'), rounding=ROUND_HALF_UP) def matches_country(self, country): if not self.area or not country or not getattr(country, 'region', None): return False region = country.region while region: if region.id == self.area.id: return True region = getattr(region, 'parent', None) return False def matches_shipment(self, shipment): location = getattr(shipment, 'to_location', None) country = getattr(location, 'country', None) return self.matches_country(country) @classmethod def compute_achieved_percent_for(cls, party, area): if not party or not area: return Decimal('0') Shipment = Pool().get('stock.shipment.in') shipments = Shipment.search([ ('controller', '!=', None), ]) execution = cls() execution.area = area shipments = [ shipment for shipment in shipments if execution.matches_shipment(shipment)] total = len(shipments) if not total: return Decimal('0') achieved = sum( 1 for shipment in shipments if shipment.controller and shipment.controller.id == party.id) return cls._round_percent( (Decimal(achieved) * Decimal('100')) / Decimal(total)) def compute_achieved_percent(self): return self.__class__.compute_achieved_percent_for( self.party, self.area) def get_target_gap(self): return self._to_decimal(self.percent) - self.compute_achieved_percent() def get_percent(self,name): return self.compute_achieved_percent() class PartyExecutionSla(ModelSQL,ModelView): "Party Execution Sla" __name__ = 'party.execution.sla' party = fields.Many2One('party.party',"Party") reference = fields.Char("Reference") product = fields.Many2One('product.product',"Product") date_from = fields.Date("From") date_to = fields.Date("To") places = fields.One2Many('party.execution.place','pes',"") class PartyExecutionPlace(ModelSQL,ModelView): "Party Sla Place" __name__ = 'party.execution.place' pes = fields.Many2One('party.execution.sla',"Sla") location = fields.Many2One('stock.location',"Location") cost = fields.Numeric("Cost",digits=(16,4)) mode = fields.Selection([ ('lumpsum', 'Lump sum'), ('perqt', 'Per qt'), ('pprice', '% price'), ('rate', '% rate'), ('pcost', '% cost price'), ('ppack', 'Per packing'), ], 'Mode', required=True) currency = fields.Many2One('currency.currency',"Currency") unit = fields.Many2One('product.uom',"Unit",domain=[ If(Eval('mode') == 'ppack', ('category', '=', 8), ()), ], states={ 'readonly': Eval('mode') != 'ppack', }) class Party(metaclass=PoolMeta): __name__ = 'party.party' tol_min = fields.Numeric("Tol - in %") tol_max = fields.Numeric("Tol + in %") wb = fields.Many2One('purchase.weight.basis',"Weight basis") association = fields.Many2One('purchase.association',"Association") origin =fields.Char("Origin") execution = fields.One2Many('party.execution','party',"") sla = fields.One2Many('party.execution.sla','party', "Sla") initial = fields.Char("Initials") def IsAvailableForControl(self,sh): return True def get_controller_execution_priority(self, shipment): best_rule = None best_gap = None for execution in self.execution or []: if not execution.matches_shipment(shipment): continue gap = execution.get_target_gap() if best_gap is None or gap > best_gap: best_gap = gap best_rule = execution return best_gap, best_rule def get_sla_cost(self,location): if self.sla: for sla in self.sla: SlaPlace = Pool().get('party.execution.place') sp = SlaPlace.search([('pes','=', sla.id),('location','=',location)]) if sp: return sp[0].cost,sp[0].mode,sp[0].currency,sp[0].unit def get_alf(self): if self.name == 'CARGO CONTROL': return 105 t = Table('alf') cursor = Transaction().connection.cursor() cursor.execute(*t.select( t.ALF_CODE, where=t.SHORT_NAME.ilike(f'%{self.name}%') )) rows = cursor.fetchall() if rows: return int(rows[0][0]) @classmethod def getPartyByName(cls, party, category=None): party = party.upper() p = cls.search([('name', '=', party)], limit=1) if p: return p[0] else: p = cls() p.name = party cls.save([p]) if category: Category = Pool().get('party.category') cat = Category.search(['name','=',category]) if cat: PartyCategory = Pool().get('party.party-party.category') pc = PartyCategory() pc.party = p.id pc.category = cat[0].id PartyCategory.save([pc]) return p