Maquila (POC)

#044178
This commit is contained in:
Raimon Esteve 2023-06-07 14:55:55 +02:00 committed by GitHub
parent 8cab6c0de8
commit 5cfc8c39e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1909 additions and 15 deletions

View File

@ -3,6 +3,7 @@
# the full copyright notices and license terms.
from trytond.pool import Pool
from . import contract
from . import maquila
from . import history
from . import party
from . import plot
@ -13,12 +14,22 @@ from . import production
from . import location
from . import move
from . import price_list
from . import sale
def register():
Pool.register(
contract.AgronomicsContractProductPriceListTypePriceList,
contract.AgronomicsContract,
contract.AgronomicsContractLine,
maquila.Configuration,
maquila.ConfigurationSequence,
maquila.Contract,
maquila.ContractCrop,
maquila.ContractProductPercentage,
maquila.ProductYear,
maquila.Maquila,
maquila.MaquilaProductYearContractCrop,
maquila.MaquilaContractCrop,
history.WineAgingHistory,
history.ProductWineAgingHistory,
party.Party,
@ -78,3 +89,10 @@ def register():
module='agronomics', type_='wizard')
Pool.register(
module='agronomics', type_='report')
Pool.register(
sale.Configuration,
sale.ConfigurationSequence,
sale.Sale,
sale.SaleLine,
module='agronomics', type_='model',
depends=['sale'])

View File

@ -174,9 +174,8 @@ class AgronomicsContractLine(ModelSQL, ModelView):
@fields.depends('parcel')
def on_change_with_product(self, name=None):
if self.parcel:
if self.parcel and self.parcel.product:
return self.parcel.product.id
return None
@fields.depends('product', methods=['on_change_with_product'])
def on_change_with_unit(self, name=None):

View File

@ -113,7 +113,7 @@ this repository contains the full copyright notices and license terms. -->
<field name="string">Done</field>
<field name="model" search="[('model', '=', 'agronomics.contract')]"/>
</record>
<record model="ir.model.button-res.group" id="purchase_contract_done_button_group_purchase">
<record model="ir.model.button-res.group" id="agronomics_contract_done_button_group_agronomics">
<field name="button" ref="agronomics_contract_done_button"/>
<field name="group" ref="group_agronomics"/>
</record>

320
doc/maquila.xml Normal file
View File

@ -0,0 +1,320 @@
<mxfile host="app.diagrams.net" modified="2023-03-28T10:30:16.678Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" etag="iX_tcFcGILS33Fjen7vQ" version="21.1.1" type="device">
<diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">
<mxGraphModel dx="1434" dy="738" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="WIyWlLk6GJQsqaUBKTNV-0" />
<mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0" />
<mxCell id="zkfFHV4jXpPFQw0GAbJ--0" value="agronomics.maquila.configuration" style="swimlane;fontStyle=2;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
<mxGeometry x="60" y="50" width="180" height="60" as="geometry">
<mxRectangle x="230" y="140" width="160" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="zkfFHV4jXpPFQw0GAbJ--1" value="contract_sequence" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
<mxGeometry y="26" width="180" height="26" as="geometry" />
</mxCell>
<mxCell id="zkfFHV4jXpPFQw0GAbJ--6" value="agronomics.maquila.contract.product_percentage" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
<mxGeometry x="647" y="194" width="260" height="104" as="geometry">
<mxRectangle x="130" y="380" width="160" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="zkfFHV4jXpPFQw0GAbJ--7" value="contract m2o" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
<mxGeometry y="26" width="260" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-51" value="product m2o" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="zkfFHV4jXpPFQw0GAbJ--6">
<mxGeometry y="52" width="260" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-52" value="percentatge" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="zkfFHV4jXpPFQw0GAbJ--6">
<mxGeometry y="78" width="260" height="26" as="geometry" />
</mxCell>
<mxCell id="zkfFHV4jXpPFQw0GAbJ--13" value="agronomics.maquila.contract.crop" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
<mxGeometry x="647" y="50" width="180" height="70" as="geometry">
<mxRectangle x="340" y="380" width="170" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="zkfFHV4jXpPFQw0GAbJ--14" value="contract" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--13" vertex="1">
<mxGeometry y="26" width="180" height="26" as="geometry" />
</mxCell>
<mxCell id="zkfFHV4jXpPFQw0GAbJ--17" value="agronomics.maquila.contract" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
<mxGeometry x="330" y="50" width="160" height="200" as="geometry">
<mxRectangle x="550" y="140" width="160" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="zkfFHV4jXpPFQw0GAbJ--18" value="product_crops o2m " style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="zkfFHV4jXpPFQw0GAbJ--19" value="product_percentages o2m" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
<mxGeometry y="52" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="zkfFHV4jXpPFQw0GAbJ--20" value="table" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
<mxGeometry y="78" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="zkfFHV4jXpPFQw0GAbJ--21" value="state" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
<mxGeometry y="104" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-6" value="number" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="zkfFHV4jXpPFQw0GAbJ--17">
<mxGeometry y="130" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-22" value="Active" style="label;whiteSpace=wrap;html=1;image=img/clipart/Gear_128x128.png" vertex="1" parent="zkfFHV4jXpPFQw0GAbJ--17">
<mxGeometry y="156" width="160" height="20" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-1" value="" style="endArrow=classic;html=1;rounded=0;endSize=8;startSize=8;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--14" target="zkfFHV4jXpPFQw0GAbJ--18">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="390" y="410" as="sourcePoint" />
<mxPoint x="440" y="360" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-2" value="" style="endArrow=classic;html=1;rounded=0;endSize=8;startSize=8;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--7" target="zkfFHV4jXpPFQw0GAbJ--19">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="590" y="290" as="sourcePoint" />
<mxPoint x="520" y="206" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-9" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--1" target="mby3T7sVTn64BkLin4Z7-6">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="220" y="100" as="sourcePoint" />
<mxPoint x="270" y="50" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-10" value="agronomics.maquila.product_year" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
<mxGeometry x="60" y="320" width="186" height="200" as="geometry">
<mxRectangle x="550" y="140" width="160" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-11" value="party m2o " style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-10">
<mxGeometry y="26" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-12" value="crop m2o" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-10">
<mxGeometry y="52" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-13" value="product m2o" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-10">
<mxGeometry y="78" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-14" value="contract_crops m2m" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-10">
<mxGeometry y="104" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-15" value="contracts o2m (function)" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-10">
<mxGeometry y="130" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-16" value="agronomics.maquila" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
<mxGeometry x="770" y="324" width="186" height="204" as="geometry">
<mxRectangle x="550" y="140" width="160" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-17" value="party m2o " style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-16">
<mxGeometry y="26" width="186" height="22" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-18" value="crop m2o" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-16">
<mxGeometry y="48" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-19" value="product m2o" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-16">
<mxGeometry y="74" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-20" value="table" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-16">
<mxGeometry y="100" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-21" value="product_year m2o" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-16">
<mxGeometry y="126" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-60" value="contract_crops m2m" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-16">
<mxGeometry y="152" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-61" value="contracts o2m (function)" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-16">
<mxGeometry y="178" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-23" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;entryX=0.989;entryY=0.06;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" target="mby3T7sVTn64BkLin4Z7-10">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="480" y="220" as="sourcePoint" />
<mxPoint x="520" y="360" as="targetPoint" />
<Array as="points">
<mxPoint x="550" y="290" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-25" value="product_percentages" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
<mxGeometry x="350" y="310" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-27" value="product_crops " style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
<mxGeometry x="365" y="298" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-31" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.025;entryY=0.055;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-15" target="zkfFHV4jXpPFQw0GAbJ--17">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="390" y="410" as="sourcePoint" />
<mxPoint x="440" y="360" as="targetPoint" />
<Array as="points">
<mxPoint x="300" y="260" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-32" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;entryX=-0.005;entryY=0.06;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" target="mby3T7sVTn64BkLin4Z7-16">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="480" y="210" as="sourcePoint" />
<mxPoint x="760" y="332" as="targetPoint" />
<Array as="points">
<mxPoint x="630" y="280" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-28" value="product_crops " style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
<mxGeometry x="647" y="310" width="100" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-33" value="party.party" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
<mxGeometry x="57" y="680" width="186" height="50" as="geometry">
<mxRectangle x="550" y="140" width="160" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-41" value="product.product" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
<mxGeometry x="317" y="680" width="186" height="52" as="geometry">
<mxRectangle x="550" y="140" width="160" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-43" value="template m2o" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-41">
<mxGeometry y="26" width="186" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-42" value="product.template" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
<mxGeometry x="647" y="680" width="186" height="50" as="geometry">
<mxRectangle x="550" y="140" width="160" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-44" value="" style="endArrow=classic;html=1;rounded=0;endSize=8;startSize=8;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-43" target="mby3T7sVTn64BkLin4Z7-42">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="390" y="430" as="sourcePoint" />
<mxPoint x="550" y="719" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-45" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-13" target="mby3T7sVTn64BkLin4Z7-41">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="390" y="430" as="sourcePoint" />
<mxPoint x="440" y="380" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-46" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-11" target="mby3T7sVTn64BkLin4Z7-33">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="390" y="430" as="sourcePoint" />
<mxPoint x="250" y="710" as="targetPoint" />
<Array as="points">
<mxPoint x="270" y="530" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-47" value="" style="edgeStyle=elbowEdgeStyle;endArrow=classic;html=1;rounded=0;endSize=8;startSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.011;entryY=0.171;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-14" target="zkfFHV4jXpPFQw0GAbJ--13">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="390" y="430" as="sourcePoint" />
<mxPoint x="580" y="60" as="targetPoint" />
<Array as="points">
<mxPoint x="530" y="250" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-48" value="" style="edgeStyle=orthogonalEdgeStyle;elbow=horizontal;endArrow=classic;html=1;rounded=0;endSize=8;startSize=8;entryX=0.806;entryY=-0.04;entryDx=0;entryDy=0;entryPerimeter=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-17" target="mby3T7sVTn64BkLin4Z7-33">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="710" y="370" as="sourcePoint" />
<mxPoint x="440" y="380" as="targetPoint" />
<Array as="points">
<mxPoint x="760" y="361" />
<mxPoint x="640" y="361" />
<mxPoint x="640" y="600" />
<mxPoint x="207" y="600" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-50" value="" style="edgeStyle=orthogonalEdgeStyle;elbow=horizontal;endArrow=classic;html=1;rounded=0;endSize=8;startSize=8;entryX=0.806;entryY=-0.04;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-19">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="770" y="410" as="sourcePoint" />
<mxPoint x="420" y="680" as="targetPoint" />
<Array as="points">
<mxPoint x="670" y="410" />
<mxPoint x="670" y="630" />
<mxPoint x="420" y="630" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-54" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;entryX=1;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-51" target="mby3T7sVTn64BkLin4Z7-41">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="390" y="430" as="sourcePoint" />
<mxPoint x="440" y="380" as="targetPoint" />
<Array as="points">
<mxPoint x="590" y="450" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-56" value="agronomics.crop" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
<mxGeometry x="1100" y="59" width="180" height="78" as="geometry">
<mxRectangle x="340" y="380" width="170" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-57" value="code" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-56">
<mxGeometry y="26" width="180" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-59" value="name" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-56">
<mxGeometry y="52" width="180" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-58" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;exitX=0.973;exitY=0.231;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-18" target="mby3T7sVTn64BkLin4Z7-57">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1010" y="370" as="sourcePoint" />
<mxPoint x="1060" y="320" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-62" value="" style="edgeStyle=elbowEdgeStyle;endArrow=classic;html=1;rounded=0;endSize=8;startSize=8;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-21" target="mby3T7sVTn64BkLin4Z7-10">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="780" y="470" as="sourcePoint" />
<mxPoint x="220" y="330" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-64" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;entryX=1;entryY=0.114;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-60" target="zkfFHV4jXpPFQw0GAbJ--13">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="450" y="430" as="sourcePoint" />
<mxPoint x="500" y="380" as="targetPoint" />
<Array as="points">
<mxPoint x="1010" y="270" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-65" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-61" target="zkfFHV4jXpPFQw0GAbJ--17">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="700" y="430" as="sourcePoint" />
<mxPoint x="750" y="380" as="targetPoint" />
<Array as="points">
<mxPoint x="1060" y="300" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-66" value="sale.sale" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
<mxGeometry x="1190" y="420" width="180" height="52" as="geometry">
<mxRectangle x="340" y="380" width="170" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-67" value="is_maquila" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-66">
<mxGeometry y="26" width="180" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-69" value="sale.line" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
<mxGeometry x="1190" y="540" width="180" height="52" as="geometry">
<mxRectangle x="340" y="380" width="170" height="26" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-70" value="maquila m2o" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="mby3T7sVTn64BkLin4Z7-69">
<mxGeometry y="26" width="180" height="26" as="geometry" />
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-71" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-70" target="mby3T7sVTn64BkLin4Z7-10">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="700" y="430" as="sourcePoint" />
<mxPoint x="140" y="520" as="targetPoint" />
<Array as="points">
<mxPoint x="420" y="510" />
<mxPoint x="530" y="550" />
<mxPoint x="620" y="500" />
<mxPoint x="1160" y="650" />
<mxPoint x="720" y="560" />
<mxPoint x="700" y="570" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="mby3T7sVTn64BkLin4Z7-74" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="mby3T7sVTn64BkLin4Z7-69" target="mby3T7sVTn64BkLin4Z7-66">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1370" y="550" as="sourcePoint" />
<mxPoint x="1420" y="500" as="targetPoint" />
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

719
maquila.py Normal file
View File

@ -0,0 +1,719 @@
from trytond.model import (Workflow, ModelSingleton, ModelView, ModelSQL,
fields, sequence_ordered)
from trytond.pyson import Id, If, Eval, Bool
from trytond.pool import Pool
from trytond.transaction import Transaction
from trytond.modules.company.model import (
CompanyMultiValueMixin, CompanyValueMixin)
from trytond.i18n import gettext
from trytond.exceptions import UserError
from trytond.model.modelstorage import AccessError
def default_func(field_name):
@classmethod
def default(cls, **pattern):
return getattr(
cls.multivalue_model(field_name),
'default_%s' % field_name, lambda: None)()
return default
class Configuration(ModelSingleton, ModelSQL, ModelView, CompanyMultiValueMixin):
"Maquila Configuration"
__name__ = 'agronomics.maquila.configuration'
contract_sequence = fields.MultiValue(fields.Many2One(
'ir.sequence', "Contract Sequence", required=True,
domain=[
('company', 'in',
[Eval('context', {}).get('company', -1), None]),
('sequence_type', '=', Id('agronomics', 'sequence_type_maquila_contract')),
]))
@classmethod
def multivalue_model(cls, field):
pool = Pool()
if field == 'contract_sequence':
return pool.get('agronomics.maquila.configuration.sequence')
return super(Configuration, cls).multivalue_model(field)
default_contract_sequence = default_func('contract_sequence')
class ConfigurationSequence(ModelSQL, CompanyValueMixin):
"Maquila Configuration Sequence"
__name__ = 'agronomics.maquila.configuration.sequence'
contract_sequence = fields.Many2One(
'ir.sequence', "Contract Sequence", required=True,
domain=[
('company', 'in', [Eval('company', -1), None]),
('sequence_type', '=', Id('agronomics', 'sequence_type_maquila_contract')),
],
depends=['company'])
@classmethod
def default_contract_sequence(cls):
pool = Pool()
ModelData = pool.get('ir.model.data')
try:
return ModelData.get_id('agronomics', 'sequence_maquila_contract')
except KeyError:
return None
class Contract(sequence_ordered(), Workflow, ModelSQL, ModelView):
"Maquila Contract"
__name__ = 'agronomics.maquila.contract'
_rec_name = 'number'
company = fields.Many2One(
'company.company', "Company", required=True, select=True,
states={
'readonly': (
(Eval('state') != 'draft')
| Eval('product_crops', [0])
| Eval('product_percentages', [0])
| Eval('product_years', [0])
| Eval('party', True)),
},
depends=['state'])
number = fields.Char('Number', readonly=True, select=True)
reference = fields.Char('Reference')
party = fields.Many2One('party.party', "Party", required=True,
states={
'readonly': Eval('state') != 'draft',
},
context={
'company': Eval('company', -1),
},
depends=['state', 'company'])
product = fields.Many2One('product.product', "Product", required=True,
domain=[
('agronomic_type', '=', 'grape'),
], states={
'readonly': Eval('state') != 'draft',
},
context={
'company': Eval('company', -1),
},
depends=['state', 'company'])
quantity = fields.Float('Quantity', required=True,
digits=(16, Eval('unit_digits', 2)),
states={
'readonly': Eval('state') != 'draft',
},
depends=['state', 'unit_digits'])
unit = fields.Many2One('product.uom', "Unit", required=True, ondelete='RESTRICT',
domain=[
If(Bool(Eval('product_uom_category')),
('category', '=', Eval('product_uom_category')),
('category', '!=', -1)),
],
states={
'readonly': Eval('state') != 'draft',
},
depends=['state', 'product_uom_category'])
unit_digits = fields.Function(fields.Integer("Unit Digits"),
'on_change_with_unit_digits')
product_uom_category = fields.Function(
fields.Many2One('product.uom.category', "Product Uom Category"),
'on_change_with_product_uom_category')
product_crops = fields.One2Many('agronomics.maquila.contract.crop',
'contract', "Product Crops",
states={
'readonly': Eval('state') != 'draft',
'required': Eval('state') == 'active',
},
depends=['state'])
product_percentages = fields.One2Many('agronomics.maquila.contract.product_percentage',
'contract', "Product Percentatges",
states={
'readonly': Eval('state') != 'draft',
'required': Eval('state') == 'active',
},
depends=['state'])
table = fields.Boolean("Table",
states={
'readonly': Eval('state') != 'draft',
},
depends=['state'])
state = fields.Selection([
('draft', "Draft"),
('active', "Active"),
('done', "Done"),
('cancelled', "Cancelled"),
], "State", readonly=True, required=True)
@classmethod
def __setup__(cls):
super(Contract, cls).__setup__()
cls._order = [
('number', 'DESC NULLS FIRST'),
('id', 'DESC'),
]
cls._transitions |= set((
('draft', 'active'),
('draft', 'cancelled'),
('active', 'done'),
('cancelled', 'draft'),
))
cls._buttons.update({
'draft': {
'invisible': Eval('state') != 'cancelled',
'icon': If(Eval('state') == 'cancelled', 'tryton-undo',
'tryton-back'),
},
'active': {
'invisible': Eval('state') != 'draft',
'icon': 'tryton-forward',
},
'cancel': {
'invisible': Eval('state') != 'draft',
'icon': 'tryton-cancel',
},
'done': {
'invisible': Eval('state') != 'active',
'icon': 'tryton-ok',
},
})
@staticmethod
def default_state():
return 'draft'
@staticmethod
def default_company():
return Transaction().context.get('company')
def get_rec_name(self, name):
items = []
if self.number:
items.append(self.number)
if self.reference:
items.append('[%s]' % self.reference)
if not items:
items.append('(%s)' % self.id)
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,
('number', operator, value),
('reference', operator, value),
]
return domain
@classmethod
def copy(cls, contracts, default=None):
if default is None:
default = {}
else:
default = default.copy()
default.setdefault('number', None)
default.setdefault('product_years', None)
default.setdefault('maquilas', None)
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')
def on_change_with_product_uom_category(self, name=None):
if self.product:
return self.product.default_uom_category.id
@fields.depends('unit')
def on_change_with_unit_digits(self, name=None):
if self.unit:
return self.unit.digits
return 2
@fields.depends('product', 'unit')
def on_change_product(self):
if not self.product:
return
category = self.product.default_uom.category
if not self.unit or self.unit.category != category:
self.unit = self.product.default_uom
self.unit_digits = self.product.default_uom.digits
@classmethod
@ModelView.button
@Workflow.transition('cancelled')
def cancel(cls, contracts):
pass
@classmethod
@ModelView.button
@Workflow.transition('draft')
def draft(cls, contracts):
pass
@classmethod
@ModelView.button
@Workflow.transition('active')
def active(cls, contracts):
for contract in contracts:
contract.check_quantity()
contract.create_contract_product_year()
contract.create_maquila()
cls.set_number(contracts)
@classmethod
@ModelView.button
@Workflow.transition('done')
def done(cls, contracts):
pass
@classmethod
def set_number(cls, contracts):
'''
Fill the number field with the contracts sequence
'''
pool = Pool()
Config = pool.get('agronomics.maquila.configuration')
config = Config(1)
for contract in contracts:
if contract.number:
continue
contract.number = config.get_multivalue(
'contract_sequence', company=contract.company.id).get()
cls.save(contracts)
def check_quantity(self):
if sum(x.quantity for x in self.product_crops) != self.quantity:
raise UserError(gettext('agronomics.msg_maquila_contract_quantity',
contract=self.rec_name))
def create_contract_product_year(self):
MaquilaProductYear = Pool().get('agronomics.maquila.product_year')
crops = set()
products = set()
for crop in self.product_crops:
crops.add(crop.crop)
for ppercentatge in self.product_percentages:
products.add(ppercentatge.product)
records = MaquilaProductYear.search([
('party', '=', self.party),
('crop', 'in', crops),
('product', 'in', products),
])
product_years = dict(((x.party, x.crop, x.product), x) for x in records)
new_product_years = []
for crop in self.product_crops:
for ppercentatge in self.product_percentages:
key = (self.party, crop.crop, ppercentatge.product)
if key in product_years:
product_year = product_years.get(key)
product_year.contract_crops += (crop,)
product_year.save()
new_product_years.append(product_year)
else:
product_year = MaquilaProductYear()
product_year.company = self.company
product_year.party = self.party
product_year.crop = crop.crop
product_year.product = ppercentatge.product
product_year.unit = ppercentatge.product.default_uom
product_year.contract_crops = (crop,)
product_year.save()
new_product_years.append(product_year)
return new_product_years
def create_maquila(self):
Maquila = Pool().get('agronomics.maquila')
default_values = Maquila.default_get(Maquila._fields.keys(),
with_rec_name=False)
crops = set()
products = set()
for crop in self.product_crops:
crops.add(crop.crop)
products.add(self.product)
records = Maquila.search([
('party', '=', self.party),
('crop', 'in', crops),
('product', 'in', products),
])
maquilas = dict(((x.party, x.product, x.crop, x.table), x) for x in records)
new_maquilas = []
for crop in self.product_crops:
key = (self.party, self.product, crop.crop, self.table)
if key in maquilas:
maquila = maquilas.get(key)
maquila.contract_crops += (crop,)
maquila.save()
new_maquilas.append(maquila)
else:
maquila = Maquila(**default_values)
maquila.company = self.company
maquila.party = self.party
maquila.crop = crop.crop
maquila.party = self.party
maquila.product = self.product
maquila.unit = self.product.default_uom
maquila.table = self.table
maquila.contract_crops = (crop,)
maquila.save()
new_maquilas.append(maquila)
return new_maquilas
class ContractCrop(ModelSQL, ModelView):
"Maquila Contract Crop"
__name__ = 'agronomics.maquila.contract.crop'
contract = fields.Many2One('agronomics.maquila.contract', "Contract",
ondelete='CASCADE', select=True, required=True)
crop = fields.Many2One('agronomics.crop', "Crop", required=True)
quantity = fields.Float("Quantity", digits=(16, 2), required=True)
penality = fields.Numeric("Penality", digits=(16, Eval('currency_digits', 2)),
depends=['currency_digits'], required=True)
currency_digits = fields.Function(fields.Integer('Currency Digits'),
'on_change_with_currency_digits')
product_years = fields.Many2Many(
'agronomics.maquila.product_year-agronomics.maquila.contract.crop',
'contract_crop', 'product_year', "Product Years")
maquilas = fields.Many2Many(
'agronomics.maquila-agronomics.maquila.contract.crop',
'contract_crop', 'maquila', "Maquila", readonly=True)
def on_change_with_currency_digits(self, name=None):
Company = Pool().get('company.company')
company = Transaction().context.get('company')
if company:
return Company(company).currency.digits
return 2
class ContractProductPercentage(ModelSQL, ModelView):
"Maquila Contract Product Percentage"
__name__ = 'agronomics.maquila.contract.product_percentage'
contract = fields.Many2One('agronomics.maquila.contract', "Contract",
ondelete='CASCADE', select=True, required=True)
product = fields.Many2One('product.product', "Product", required=True)
percentatge = fields.Float("Percentatge", digits=(16, 2), required=True)
class ProductYear(ModelSQL, ModelView):
"Maquila Product Year"
__name__ = 'agronomics.maquila.product_year'
company = fields.Many2One(
'company.company', "Company", required=True, select=True, readonly=True)
party = fields.Many2One('party.party', "Party", required=True, readonly=True,
context={
'company': Eval('company', -1),
},
depends=['company'])
crop = fields.Many2One('agronomics.crop', "Crop", required=True,
readonly=True)
product = fields.Many2One('product.product', "Product", required=True,
readonly=True, context={
'company': Eval('company', None),
}, depends=['company'])
quantity = fields.Function(fields.Float("Quantity",
digits=(16, Eval('unit_digits', 2)),
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')
pending_delivered_quantity = fields.Function(fields.Float(
"Pending Delivered Quantity",
digits=(16, Eval('unit_digits', 2)),
depends=['unit_digits']), 'get_delivered_quantity')
unit = fields.Many2One('product.uom', "Unit", required=True, readonly=True,
ondelete='RESTRICT', domain=[
If(Bool(Eval('product_uom_category')),
('category', '=', Eval('product_uom_category')),
('category', '!=', -1)),
],
depends=['product_uom_category'])
unit_digits = fields.Function(fields.Integer("Unit Digits"),
'on_change_with_unit_digits')
product_uom_category = fields.Function(
fields.Many2One('product.uom.category', "Product Uom Category"),
'on_change_with_product_uom_category')
contract_crops = fields.Many2Many(
'agronomics.maquila.product_year-agronomics.maquila.contract.crop',
'product_year', 'contract_crop', "Contract Crops", readonly=True)
contracts = fields.Function(fields.One2Many('agronomics.maquila.contract',
None, "Contracts"), 'get_contracts', searcher='search_contracts')
@classmethod
def __setup__(cls):
super(ProductYear, cls).__setup__()
cls._order = [
('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')
def on_change_with_product_uom_category(self, name=None):
if self.product:
return self.product.default_uom_category.id
@fields.depends('unit')
def on_change_with_unit_digits(self, name=None):
if self.unit:
return self.unit.digits
return 2
@fields.depends('product', 'unit')
def on_change_product(self):
if not self.product:
return
category = self.product.default_uom.category
if not self.unit or self.unit.category != category:
self.unit = self.product.default_uom
self.unit_digits = self.product.default_uom.digits
@classmethod
def get_quantity(cls, product_years, name):
res = dict((x.id, 0) for x in product_years)
for product_year in product_years:
_sum = 0
for crop in product_year.contract_crops:
for ppercentatge in crop.contract.product_percentages:
if ppercentatge.product == product_year.product:
_sum += crop.quantity * ppercentatge.percentatge
res[product_year.id] = _sum
return res
@classmethod
def get_delivered_quantity(cls, product_years, names):
pool = Pool()
SaleLine = pool.get('sale.line')
Uom = pool.get('product.uom')
res = {n: {r.id: 0 for r in product_years} for n in names}
# get qty delivered from sales (moves)
product_years_delivered = {}
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)
product_years_delivered[product_year.id] = _sum
for name in names:
for product_year in product_years:
delivered_quantity = product_years_delivered.get(product_year.id, 0)
if name == 'delivered_quantity':
res[name][product_year.id] = delivered_quantity
elif name == 'pending_delivered_quantity':
# TODO total qty from?
res[name][product_year.id] = product_year.quantity - delivered_quantity
return res
@classmethod
def get_contracts(cls, product_years, name):
res = dict((x.id, None) for x in product_years)
for product_year in product_years:
contracts = [crop.contract.id for crop in product_year.contract_crops]
res[product_year.id] = contracts
return res
@classmethod
def search_contracts(cls, name, clause):
return [('contract_crops.contract',) + tuple(clause[1:])]
class Maquila(ModelSQL, ModelView):
"Maquila"
__name__ = 'agronomics.maquila'
company = fields.Many2One(
'company.company', "Company", required=True, select=True, readonly=True)
crop = fields.Many2One('agronomics.crop', "Crop", required=True, readonly=True)
party = fields.Many2One('party.party', "Party", required=True, readonly=True,
context={
'company': Eval('company', -1),
},
depends=['company'])
quantity = fields.Function(fields.Float("Quantity",
digits=(16, Eval('unit_digits', 2)),
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,
readonly=True,
context={
'company': Eval('company', -1),
},
depends=['company'])
unit = fields.Many2One('product.uom', "Unit", required=True, readonly=True,
ondelete='RESTRICT', domain=[
If(Bool(Eval('product_uom_category')),
('category', '=', Eval('product_uom_category')),
('category', '!=', -1)),
],
depends=['product_uom_category'])
unit_digits = fields.Function(fields.Integer("Unit Digits"),
'on_change_with_unit_digits')
product_uom_category = fields.Function(
fields.Many2One('product.uom.category', "Product Uom Category"),
'on_change_with_product_uom_category')
weighings = fields.One2Many('agronomics.weighing', 'maquila',
"Weighings", readonly=True)
product_year = fields.Many2One('agronomics.maquila.product_year',
"Product Year", readonly=True)
table = fields.Boolean("Table", readonly=True)
contract_crops = fields.Many2Many(
'agronomics.maquila-agronomics.maquila.contract.crop',
'maquila', 'contract_crop', "Contract Crops", readonly=True)
contracts = fields.Function(fields.One2Many('agronomics.maquila.contract',
None, "Contracts"), 'get_contracts', searcher='search_contracts')
@staticmethod
def default_company():
return Transaction().context.get('company')
@classmethod
def __setup__(cls):
super(Maquila, cls).__setup__()
cls._order = [
('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')
def on_change_with_product_uom_category(self, name=None):
if self.product:
return self.product.default_uom_category.id
@fields.depends('unit')
def on_change_with_unit_digits(self, name=None):
if self.unit:
return self.unit.digits
return 2
@classmethod
def get_quantity(cls, maquilas, name):
res = dict((x.id, 0) for x in maquilas)
for maquila in maquilas:
_sum = 0
for crop in maquila.contract_crops:
if crop.contract.product == maquila.product:
_sum += crop.quantity
res[maquila.id] = _sum
return res
@classmethod
def get_pending_quantity(cls, maquilas, name):
pool = Pool()
Weighing = pool.get('agronomics.weighing')
Uom = pool.get('product.uom')
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
@classmethod
def search_contracts(cls, name, clause):
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)

427
maquila.xml Normal file
View File

@ -0,0 +1,427 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<menuitem name="Maquila" sequence="80" id="menu_maquila"
parent="menu_agronomics"/>
<record model="ir.ui.menu-res.group" id="menu_maquila_group_agronomics">
<field name="menu" ref="menu_maquila"/>
<field name="group" ref="group_agronomics"/>
</record>
<record model="ir.sequence.type" id="sequence_type_maquila_contract">
<field name="name">Maquila Contract</field>
</record>
<record model="ir.sequence.type-res.group" id="sequence_type_maquila_contract_group_admin">
<field name="sequence_type" ref="sequence_type_maquila_contract"/>
<field name="group" ref="res.group_admin"/>
</record>
<record model="ir.sequence.type-res.group" id="sequence_type_maquila_contractgroup_agronomics_admin">
<field name="sequence_type" ref="sequence_type_maquila_contract"/>
<field name="group" ref="group_agronomics_admin"/>
</record>
<record model="ir.sequence" id="sequence_maquila_contract">
<field name="name">Maquila Contract</field>
<field name="sequence_type" ref="sequence_type_maquila_contract"/>
</record>
<!-- maquila.configuration -->
<record model="ir.ui.view" id="maquila_configuration_view_form">
<field name="model">agronomics.maquila.configuration</field>
<field name="type">form</field>
<field name="name">maquila_configuration_form</field>
</record>
<record model="ir.action.act_window" id="act_maquila_configuration_form">
<field name="name">Maquila Configuration</field>
<field name="res_model">agronomics.maquila.configuration</field>
</record>
<record model="ir.action.act_window.view" id="act_maquila_configuration_view1">
<field name="sequence" eval="1"/>
<field name="view" ref="maquila_configuration_view_form"/>
<field name="act_window" ref="act_maquila_configuration_form"/>
</record>
<menuitem
parent="menu_configuration"
action="act_maquila_configuration_form"
sequence="10"
id="menu_maquila_configuration"
icon="tryton-list"/>
<record model="ir.model.access" id="access_maquila_configuration">
<field name="model" search="[('model', '=', 'agronomics.maquila.configuration')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_maquila_configuration_maquila_admin">
<field name="model" search="[('model', '=', 'agronomics.maquila.configuration')]"/>
<field name="group" ref="group_agronomics_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- agronomics.maquila.contract -->
<record model="ir.ui.view" id="maquila_contract_view_form">
<field name="model">agronomics.maquila.contract</field>
<field name="type">form</field>
<field name="name">maquila_contract_form</field>
</record>
<record model="ir.ui.view" id="maquila_contract_view_tree">
<field name="model">agronomics.maquila.contract</field>
<field name="type">tree</field>
<field name="priority" eval="20"/>
<field name="name">maquila_contract_list</field>
</record>
<record model="ir.action.act_window" id="act_maquila_contract_form">
<field name="name">Maquila Contracts</field>
<field name="res_model">agronomics.maquila.contract</field>
</record>
<record model="ir.action.act_window.view" id="act_maquila_contract_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="maquila_contract_view_tree"/>
<field name="act_window" ref="act_maquila_contract_form"/>
</record>
<record model="ir.action.act_window.view" id="act_maquila_contract_tree_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="maquila_contract_view_form"/>
<field name="act_window" ref="act_maquila_contract_form"/>
</record>
<record model="ir.action.act_window.domain" id="act_maquila_contract_draft">
<field name="name">Draft</field>
<field name="sequence" eval="10"/>
<field name="domain" eval="[('state', '=', 'draft')]" pyson="1"/>
<field name="act_window" ref="act_maquila_contract_form"/>
</record>
<record model="ir.action.act_window.domain" id="act_maquila_contract_active">
<field name="name">Active</field>
<field name="sequence" eval="20"/>
<field name="domain" eval="[('state', '=', 'active')]" pyson="1"/>
<field name="act_window" ref="act_maquila_contract_form"/>
</record>
<record model="ir.action.act_window.domain" id="act_maquila_contract_all">
<field name="name">All</field>
<field name="sequence" eval="30"/>
<field name="domain"></field>
<field name="act_window" ref="act_maquila_contract_form"/>
</record>
<menuitem parent="menu_maquila" sequence="1"
action="act_maquila_contract_form" id="menu_maquila_contract_list"/>
<record model="ir.model.button" id="maquila_contract_cancel_button">
<field name="name">cancel</field>
<field name="string">Cancel</field>
<field name="model" search="[('model', '=', 'agronomics.maquila.contract')]"/>
</record>
<record model="ir.model.button-res.group" id="maquila_contract_cancel_button_group_agronomics">
<field name="button" ref="maquila_contract_cancel_button"/>
<field name="group" ref="group_agronomics"/>
</record>
<record model="ir.model.button" id="maquila_contract_active_button">
<field name="name">active</field>
<field name="string">Active</field>
<field name="model" search="[('model', '=', 'agronomics.maquila.contract')]"/>
</record>
<record model="ir.model.button-res.group" id="maquila_contract_active_button_group_agronomics">
<field name="button" ref="maquila_contract_active_button"/>
<field name="group" ref="group_agronomics"/>
</record>
<record model="ir.model.button" id="maquila_contract_draft_button">
<field name="name">draft</field>
<field name="string">Draft</field>
<field name="model" search="[('model', '=', 'agronomics.maquila.contract')]"/>
</record>
<record model="ir.model.button-res.group" id="maquila_contract_draft_button_group_agronomics">
<field name="button" ref="maquila_contract_draft_button"/>
<field name="group" ref="group_agronomics"/>
</record>
<record model="ir.model.button" id="maquila_contract_done_button">
<field name="name">done</field>
<field name="string">Done</field>
<field name="model" search="[('model', '=', 'agronomics.maquila.contract')]"/>
</record>
<record model="ir.model.button-res.group" id="maquila_contract_done_button_group_agronomics">
<field name="button" ref="maquila_contract_done_button"/>
<field name="group" ref="group_agronomics"/>
</record>
<record model="ir.model.access" id="access_maquila_contract">
<field name="model" search="[('model', '=', 'agronomics.maquila.contract')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_maquila_contract_agronomics">
<field name="model" search="[('model', '=', 'agronomics.maquila.contract')]"/>
<field name="group" ref="agronomics.group_agronomics"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.model.access" id="access_maquila_contract_admin">
<field name="model" search="[('model', '=', 'agronomics.maquila.contract')]"/>
<field name="group" ref="agronomics.group_agronomics_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.rule.group" id="rule_group_maquila_contract_companies">
<field name="name">User in companies</field>
<field name="model" search="[('model', '=', 'agronomics.maquila.contract')]"/>
<field name="global_p" eval="True"/>
</record>
<record model="ir.rule" id="rule_maquila_contract_companies">
<field name="domain"
eval="[('company', 'in', Eval('companies', []))]"
pyson="1"/>
<field name="rule_group" ref="rule_group_maquila_contract_companies"/>
</record>
<record model="ir.action.act_window" id="act_maquila_contract_maquila_product_year_form">
<field name="name">Product Years</field>
<field name="res_model">agronomics.maquila.product_year</field>
<field name="domain"
eval="[If(Eval('active_ids', []) == [Eval('active_id')], ('contract_crops.contract', '=', Eval('active_id')), ('contract_crops.contract', 'in', Eval('active_ids')))]"
pyson="1"/>
</record>
<record model="ir.action.keyword" id="act_open_maquila_contract_maquila_product_year_keyword1">
<field name="keyword">form_relate</field>
<field name="model">agronomics.maquila.contract,-1</field>
<field name="action" ref="act_maquila_contract_maquila_product_year_form"/>
</record>
<record model="ir.action.act_window" id="act_maquila_contract_maquila_form">
<field name="name">Maquilas</field>
<field name="res_model">agronomics.maquila</field>
<field name="domain"
eval="[If(Eval('active_ids', []) == [Eval('active_id')], ('contract_crops.contract', '=', Eval('active_id')), ('contract_crops.contract', 'in', Eval('active_ids')))]"
pyson="1"/>
</record>
<record model="ir.action.keyword" id="act_open_maquila_contract_maquila_keyword1">
<field name="keyword">form_relate</field>
<field name="model">agronomics.maquila.contract,-1</field>
<field name="action" ref="act_maquila_contract_maquila_form"/>
</record>
<!-- agronomics.maquila.contract.crop -->
<record model="ir.ui.view" id="maquila_contract_crop_view_form">
<field name="model">agronomics.maquila.contract.crop</field>
<field name="type">form</field>
<field name="name">maquila_contract_crop_form</field>
</record>
<record model="ir.ui.view" id="maquila_contract_crop_view_tree">
<field name="model">agronomics.maquila.contract.crop</field>
<field name="type">tree</field>
<field name="priority" eval="20"/>
<field name="name">maquila_contract_crop_list</field>
</record>
<record model="ir.action.act_window" id="act_maquila_contract_crop_form">
<field name="name">Maquila Contract Crops</field>
<field name="res_model">agronomics.maquila.contract.crop</field>
</record>
<record model="ir.action.act_window.view" id="act_maquila_contract_crop_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="maquila_contract_crop_view_tree"/>
<field name="act_window" ref="act_maquila_contract_crop_form"/>
</record>
<record model="ir.action.act_window.view" id="act_maquila_contract_crop_tree_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="maquila_contract_crop_view_form"/>
<field name="act_window" ref="act_maquila_contract_crop_form"/>
</record>
<!-- agronomics.maquila.contract.product_percentage -->
<record model="ir.ui.view" id="maquila_contract_product_percentage_view_form">
<field name="model">agronomics.maquila.contract.product_percentage</field>
<field name="type">form</field>
<field name="name">maquila_contract_product_percentage_form</field>
</record>
<record model="ir.ui.view" id="maquila_contract_product_percentage_view_tree">
<field name="model">agronomics.maquila.contract.product_percentage</field>
<field name="type">tree</field>
<field name="priority" eval="20"/>
<field name="name">maquila_contract_product_percentage_list</field>
</record>
<record model="ir.action.act_window" id="act_maquila_contract_product_percentage_form">
<field name="name">Maquila Contract Product Percentage</field>
<field name="res_model">agronomics.maquila.contract.product_percentage</field>
</record>
<record model="ir.action.act_window.view" id="act_maquila_contract_product_percentage_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="maquila_contract_product_percentage_view_tree"/>
<field name="act_window" ref="act_maquila_contract_product_percentage_form"/>
</record>
<record model="ir.action.act_window.view" id="act_maquila_contract_product_percentage_tree_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="maquila_contract_product_percentage_view_form"/>
<field name="act_window" ref="act_maquila_contract_product_percentage_form"/>
</record>
<!-- agronomics.maquila.product_year -->
<record model="ir.ui.view" id="maquila_product_year_view_form">
<field name="model">agronomics.maquila.product_year</field>
<field name="type">form</field>
<field name="name">maquila_product_year_form</field>
</record>
<record model="ir.ui.view" id="maquila_product_year_view_tree">
<field name="model">agronomics.maquila.product_year</field>
<field name="type">tree</field>
<field name="priority" eval="20"/>
<field name="name">maquila_product_year_list</field>
</record>
<record model="ir.action.act_window" id="act_maquila_product_year_form">
<field name="name">Maquila Product Year</field>
<field name="res_model">agronomics.maquila.product_year</field>
</record>
<record model="ir.action.act_window.view" id="act_maquila_product_year_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="maquila_product_year_view_tree"/>
<field name="act_window" ref="act_maquila_product_year_form"/>
</record>
<record model="ir.action.act_window.view" id="act_maquila_product_year_tree_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="maquila_product_year_view_form"/>
<field name="act_window" ref="act_maquila_product_year_form"/>
</record>
<menuitem parent="menu_maquila" sequence="20"
action="act_maquila_product_year_form" id="menu_maquila_product_year_list"/>
<record model="ir.model.access" id="access_maquila_product_year">
<field name="model" search="[('model', '=', 'agronomics.maquila.product_year')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_maquila_product_year_agronomics">
<field name="model" search="[('model', '=', 'agronomics.maquila.product_year')]"/>
<field name="group" ref="agronomics.group_agronomics"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_maquila_product_year_admin">
<field name="model" search="[('model', '=', 'agronomics.maquila.product_year')]"/>
<field name="group" ref="agronomics.group_agronomics_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.rule.group" id="rule_group_maquila_product_year_companies">
<field name="name">User in companies</field>
<field name="model" search="[('model', '=', 'agronomics.maquila.product_year')]"/>
<field name="global_p" eval="True"/>
</record>
<record model="ir.rule" id="rule_maquila_product_year_companies">
<field name="domain"
eval="[('company', 'in', Eval('companies', []))]"
pyson="1"/>
<field name="rule_group" ref="rule_group_maquila_product_year_companies"/>
</record>
<!-- agronomics.maquila -->
<record model="ir.ui.view" id="maquila_view_form">
<field name="model">agronomics.maquila</field>
<field name="type">form</field>
<field name="name">maquila_form</field>
</record>
<record model="ir.ui.view" id="maquila_view_tree">
<field name="model">agronomics.maquila</field>
<field name="type">tree</field>
<field name="priority" eval="20"/>
<field name="name">maquila_list</field>
</record>
<record model="ir.action.act_window" id="act_maquila_form">
<field name="name">Maquila</field>
<field name="res_model">agronomics.maquila</field>
</record>
<record model="ir.action.act_window.view" id="act_maquila_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="maquila_view_tree"/>
<field name="act_window" ref="act_maquila_form"/>
</record>
<record model="ir.action.act_window.view" id="act_maquila_tree_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="maquila_view_form"/>
<field name="act_window" ref="act_maquila_form"/>
</record>
<menuitem parent="menu_maquila" sequence="30"
action="act_maquila_form" id="menu_maquila_list"/>
<record model="ir.model.access" id="access_maquila">
<field name="model" search="[('model', '=', 'agronomics.maquila')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_maquila_agronomics">
<field name="model" search="[('model', '=', 'agronomics.maquila')]"/>
<field name="group" ref="agronomics.group_agronomics"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.model.access" id="access_maquila_admin">
<field name="model" search="[('model', '=', 'agronomics.maquila')]"/>
<field name="group" ref="agronomics.group_agronomics_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.rule.group" id="rule_group_maquila_companies">
<field name="name">User in companies</field>
<field name="model" search="[('model', '=', 'agronomics.maquila')]"/>
<field name="global_p" eval="True"/>
</record>
<record model="ir.rule" id="rule_maquila_companies">
<field name="domain"
eval="[('company', 'in', Eval('companies', []))]"
pyson="1"/>
<field name="rule_group" ref="rule_group_maquila_companies"/>
</record>
<record model="ir.action.act_window" id="act_maquila_weighing_form2">
<field name="name">Weighings</field>
<field name="res_model">agronomics.weighing</field>
<field name="domain"
eval="[If(Eval('active_ids', []) == [Eval('active_id')], ('maquila', '=', Eval('active_id')), ('maquila', 'in', Eval('active_ids')))]"
pyson="1"/>
</record>
<record model="ir.action.keyword" id="act_open_maquila_weighing_keyword1">
<field name="keyword">form_relate</field>
<field name="model">agronomics.maquila,-1</field>
<field name="action" ref="act_maquila_weighing_form2"/>
</record>
<record model="ir.action-res.group" id="act_maquila_weighing_form2-group_agronomics">
<field name="action" ref="act_maquila_weighing_form2"/>
<field name="group" ref="group_agronomics"/>
</record>
</data>
</tryton>

View File

@ -51,5 +51,11 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.message" id="msg_parcel_without_current_crop">
<field name="text">The plantation "%(plantation)s" in the weighing "%(weighing)s" has no parcel of the weighing's crop.</field>
</record>
<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>
</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>
</tryton>

View File

@ -136,7 +136,8 @@ class Parcel(ModelSQL, ModelView):
)*self.surface, 2)
def get_purchased_quantity(self, name):
return sum([w.netweight for w in self.weighings if not w.table])
return sum([w.netweight for w in self.weighings
if w.netweight and not w.table])
def get_remaining_quantity(self, name):
return (self.max_production or 0) - (self.purchased_quantity or 0)

125
sale.py Normal file
View File

@ -0,0 +1,125 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import fields
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval, Id, If
def default_func(field_name):
@classmethod
def default(cls, **pattern):
return getattr(
cls.multivalue_model(field_name),
'default_%s' % field_name, lambda: None)()
return default
class Configuration(metaclass=PoolMeta):
__name__ = 'sale.configuration'
maquila_sale_sequence = fields.MultiValue(fields.Many2One(
'ir.sequence', "Maquila Sale Sequence", required=True,
domain=[
('company', 'in',
[Eval('context', {}).get('company', -1), None]),
('sequence_type', '=', Id('agronomics', 'sequence_type_maquila_sale')),
]))
@classmethod
def multivalue_model(cls, field):
pool = Pool()
if field == 'maquila_sale_sequence':
return pool.get('sale.configuration.sequence')
return super(Configuration, cls).multivalue_model(field)
default_maquila_sale_sequence = default_func('maquila_sale_sequence')
class ConfigurationSequence(metaclass=PoolMeta):
__name__ = 'sale.configuration.sequence'
maquila_sale_sequence = fields.Many2One(
'ir.sequence', "Maquila Sale Sequence", required=True,
domain=[
('company', 'in', [Eval('company', -1), None]),
('sequence_type', '=', Id('agronomics', 'sequence_type_maquila_sale')),
],
depends=['company'])
@classmethod
def default_maquila_sale_sequence(cls):
pool = Pool()
ModelData = pool.get('ir.model.data')
try:
return ModelData.get_id('agronomics', 'sequence_maquila_sale')
except KeyError:
return None
class Sale(metaclass=PoolMeta):
__name__ = 'sale.sale'
is_maquila = fields.Boolean("Is Maquila",
states={
'readonly': ((Eval('state') != 'draft') | (Eval('lines', [0]))),
},
depends=['state'])
@fields.depends('is_maquila')
def on_change_is_maquila(self):
self.invoice_method = ('manual' if self.is_maquila
else self.default_invoice_method())
@fields.depends('is_maquila')
def on_change_party(self):
super().on_change_party()
if self.is_maquila:
self.on_change_is_maquila()
@classmethod
def set_number(cls, sales):
pool = Pool()
Config = pool.get('sale.configuration')
config = Config(1)
for sale in sales:
if sale.number:
continue
if sale.is_maquila:
sale.number = config.get_multivalue(
'maquila_sale_sequence', company=sale.company.id).get()
super().set_number(sales)
class SaleLine(metaclass=PoolMeta):
__name__ = 'sale.line'
maquila = fields.Many2One('agronomics.maquila.product_year', "Maquila",
domain=[
('product', '=', Eval('product')),
('party', '=', Eval('_parent_sale', {}).get('party')),
],
states={
'invisible': ~Bool(Eval('_parent_sale', {}).get('is_maquila')),
'required': Bool(Eval('_parent_sale', {}).get('is_maquila')),
'readonly': Eval('sale_state') != 'draft',
})
liter_uom = fields.Function(fields.Many2One('product.uom', "Liter Uom"),
'get_liter_uom')
@classmethod
def __setup__(cls):
super(SaleLine, cls).__setup__()
cls.product.domain += [If( Bool(Eval('_parent_sale', {}).get('is_maquila')),
('sale_uom', '=', Eval('liter_uom')),
())]
cls.product.depends += ['liter_uom']
@classmethod
def default_liter_uom(cls):
pool = Pool()
ModelData = pool.get('ir.model.data')
uom_liter_id = ModelData.get_id('product', 'uom_liter')
return uom_liter_id
@classmethod
def get_liter_uom(cls, lines, name):
uom_liter_id = cls.default_liter_uom()
return dict((x.id, uom_liter_id) for x in lines)

51
sale.xml Normal file
View File

@ -0,0 +1,51 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data depends="sale">
<!-- maquila sale sequence -->
<record model="ir.sequence.type" id="sequence_type_maquila_sale">
<field name="name">Maquila Sale</field>
</record>
<record model="ir.sequence.type-res.group" id="sequence_type_maquila_sale_group_admin">
<field name="sequence_type" ref="sequence_type_maquila_sale"/>
<field name="group" ref="res.group_admin"/>
</record>
<record model="ir.sequence.type-res.group" id="sequence_type_maquila_salegroup_agronomics_admin">
<field name="sequence_type" ref="sequence_type_maquila_sale"/>
<field name="group" ref="group_agronomics_admin"/>
</record>
<record model="ir.sequence" id="sequence_maquila_sale">
<field name="name">Maquila Sale</field>
<field name="sequence_type" ref="sequence_type_maquila_sale"/>
</record>
<record model="ir.ui.view" id="sale_configuration_view_form">
<field name="model">sale.configuration</field>
<field name="inherit" ref="sale.sale_configuration_view_form"/>
<field name="name">sale_configuration_form</field>
</record>
<record model="ir.ui.view" id="sale_view_tree">
<field name="model">sale.sale</field>
<field name="inherit" ref="sale.sale_view_tree"/>
<field name="name">sale_tree</field>
</record>
<record model="ir.ui.view" id="sale_view_form">
<field name="model">sale.sale</field>
<field name="inherit" ref="sale.sale_view_form"/>
<field name="name">sale_form</field>
</record>
<record model="ir.ui.view" id="sale_line_view_tree_sequence">
<field name="model">sale.line</field>
<field name="inherit" ref="sale.sale_line_view_tree_sequence"/>
<field name="name">sale_line_tree_sequence</field>
</record>
<record model="ir.ui.view" id="sale_line_view_form">
<field name="model">sale.line</field>
<field name="inherit" ref="sale.sale_line_view_form"/>
<field name="name">sale_line_form</field>
</record>
</data>
</tryton>

View File

@ -3,6 +3,7 @@ version=6.0.0
depends:
ir
res
company
party
product_classification
product_classification_taxonomic
@ -12,6 +13,8 @@ depends:
production
stock
account_invoice_line_standalone
extras_depend:
sale
xml:
plot.xml
party.xml
@ -23,4 +26,6 @@ xml:
location.xml
quality.xml
contract.xml
maquila.xml
sale.xml
history.xml

View File

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<form>
<label name="contract_sequence"/>
<field name="contract_sequence"/>
</form>

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<form>
<label name="contract"/>
<field name="contract" colspan="3"/>
<label name="crop"/>
<field name="crop"/>
<label name="quantity"/>
<field name="quantity"/>
<label name="penality"/>
<field name="penality"/>
<newline/>
<field name="product_years" colspan="6"/>
<field name="maquilas" colspan="6"/>
</form>

View File

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<tree>
<field name="contract"/>
<field name="crop"/>
<field name="quantity"/>
<field name="penality"/>
</tree>

View File

@ -0,0 +1,37 @@
<?xml version="1.0"?>
<form>
<label name="number"/>
<field name="number"/>
<label name="reference"/>
<field name="reference"/>
<label name="party"/>
<field name="party"/>
<label name="product"/>
<field name="product"/>
<label name="company"/>
<field name="company"/>
<label name="quantity"/>
<field name="quantity"/>
<label name="unit"/>
<field name="unit"/>
<label name="table"/>
<field name="table"/>
<label name="company"/>
<field name="company"/>
<notebook colspan="4">
<page name="product_crops">
<field name="product_crops"/>
</page>
<page name="product_percentages">
<field name="product_percentages"/>
</page>
</notebook>
<group col="6" colspan="6" id="server_buttons">
<label name="state"/>
<field name="state"/>
<button name="draft"/>
<button name="active"/>
<button name="cancel"/>
<button name="done"/>
</group>
</form>

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<tree>
<field name="number"/>
<field name="party"/>
<field name="product"/>
<field name="quantity"/>
<field name="table"/>
<field name="state"/>
<field name="company"/>
<field name="reference"/>
</tree>

View File

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<form>
<label name="contract"/>
<field name="contract" colspan="3"/>
<label name="product"/>
<field name="product"/>
<label name="percentatge"/>
<field name="percentatge" factor="100"/>
</form>

View File

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<tree>
<field name="contract"/>
<field name="product"/>
<field name="percentatge" factor="100"/>
</tree>

22
view/maquila_form.xml Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<form>
<label name="party"/>
<field name="party"/>
<label name="company"/>
<field name="company"/>
<label name="crop"/>
<field name="crop"/>
<label name="table"/>
<field name="table"/>
<label name="product"/>
<field name="product"/>
<label name="unit"/>
<field name="unit"/>
<label name="quantity"/>
<field name="quantity"/>
<label name="pending_quantity"/>
<field name="pending_quantity"/>
<newline/>
<field name="contract_crops" colspan="6"/>
<field name="contracts" colspan="6"/>
</form>

11
view/maquila_list.xml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<tree>
<field name="party"/>
<field name="crop"/>
<field name="table"/>
<field name="product"/>
<field name="quantity"/>
<field name="unit"/>
<field name="company"/>
<field name="contracts" tree_invisible="1"/>
</tree>

View File

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<form>
<label name="party"/>
<field name="party"/>
<label name="company"/>
<field name="company"/>
<label name="crop"/>
<field name="crop"/>
<label name="product"/>
<field name="product"/>
<label name="quantity"/>
<field name="quantity"/>
<label name="unit"/>
<field name="unit"/>
<label name="delivered_quantity"/>
<field name="delivered_quantity"/>
<label name="pending_delivered_quantity"/>
<field name="pending_delivered_quantity"/>
<newline/>
<field name="contract_crops" colspan="6"/>
<field name="contracts" colspan="6"/>
</form>

View File

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<tree>
<field name="party"/>
<field name="crop"/>
<field name="product"/>
<field name="quantity"/>
<field name="unit"/>
<field name="contracts" tree_invisible="1"/>
</tree>

View File

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<data>
<xpath expr="/form" position="inside">
<label name="maquila_sale_sequence"/>
<field name="maquila_sale_sequence"/>
</xpath>
</data>

9
view/sale_form.xml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/form/field[@name='reference']" position="after">
<label name="is_maquila"/>
<field name="is_maquila"/>
</xpath>
</data>

9
view/sale_line_form.xml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/form/notebook/page[@id='general']/field[@name='amount']" position="after">
<label name="maquila"/>
<field name="maquila"/>
</xpath>
</data>

View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/tree/field[@name='amount']" position="after">
<field name="maquila"/>
</xpath>
</data>

8
view/sale_tree.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/tree/field[@name='description']" position="after">
<field name="is_maquila" tree_invisible="1"/>
</xpath>
</data>

View File

@ -15,6 +15,10 @@
<field name="variety"/>
<label name="table"/>
<field name="table"/>
<label name="is_maquila"/>
<field name="is_maquila"/>
<label name="maquila"/>
<field name="maquila"/>
<label name="ecological"/>
<field name="ecological"/>
<group col="6" colspan="4" id="weight">
@ -31,7 +35,6 @@
<field name="quality_test"/>
<label name="inventory_move"/>
<field name="inventory_move"/>
<notebook>
<page name="plantations">
<field name="plantations" colspan="4"/>

View File

@ -1,7 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import fields, ModelSQL, ModelView, Workflow, sequence_ordered
from trytond.pyson import Id, Eval, If
from trytond.pyson import Bool, Id, Eval, If
from trytond.pool import Pool
from trytond.i18n import gettext
from trytond.exceptions import UserError
@ -25,6 +25,7 @@ class WeighingCenter(ModelSQL, ModelView):
READONLY = ['processing', 'distributed', 'in_analysis', 'done', 'cancelled']
READONLY2 = ['draft', 'distributed', 'in_analysis', 'done', 'cancelled']
class Weighing(Workflow, ModelSQL, ModelView):
""" Weighing """
__name__ = 'agronomics.weighing'
@ -83,7 +84,8 @@ class Weighing(Workflow, ModelSQL, ModelView):
'Beneficiaries', states={
'readonly': Eval('state').in_(READONLY2),
'required': Eval('state') == 'in_analysis',
})
'invisible': Eval('is_maquila', True),
}, depends=['is_maquila', 'state'])
denomination_origin = fields.Many2Many('agronomics.weighing-agronomics.do',
'weighing', 'do', 'Denomination of Origin', states={
'readonly': Eval('state').in_(READONLY2),
@ -91,7 +93,9 @@ class Weighing(Workflow, ModelSQL, ModelView):
})
beneficiaries_invoices_line = fields.Many2Many(
'agronomics.weighing-account.invoice.line', 'weighing', 'invoice_line',
"Beneficiaries Invoices", readonly=True)
"Beneficiaries Invoices", readonly=True, states={
'invisible': Eval('is_maquila', True),
}, depends=['is_maquila'])
plantations = fields.One2Many('agronomics.weighing-agronomics.plantation',
'weighing', 'plantations', states={
'readonly': Eval('state').in_(READONLY),
@ -121,7 +125,20 @@ class Weighing(Workflow, ModelSQL, ModelView):
forced_analysis = fields.Boolean('Forced Analysis', readonly=True)
inventory_move = fields.Many2One('stock.move', "Inventory Move",
readonly=True)
is_maquila = fields.Boolean("Is Maquila", states={
'readonly': Eval('state').in_(READONLY),
}, depends=['state'])
# TODO weighing table is readonly when is draft
maquila = fields.Many2One('agronomics.maquila', "Maquila",
domain=[
('table', '=', Bool(Eval('table', False))),
('product', '=', Eval('product')),
],
states={
'readonly': Eval('state').in_(['in_analysis', 'done', 'cancelled']),
'invisible': ~Eval('is_maquila', False),
'required': (Bool(Eval('is_maquila', False)) & (Eval('state') == 'in_analysis')),
}, depends=['is_maquila', 'table', 'product', 'state'])
@classmethod
def __setup__(cls):
@ -398,7 +415,8 @@ class Weighing(Workflow, ModelSQL, ModelView):
cls.analysis(to_analysis)
def get_not_assigned_weight(self, name):
return self.netweight - sum([p.netweight for p in self.parcels])
if self.netweight:
return self.netweight - sum([p.netweight or 0 for p in self.parcels])
@classmethod
@ModelView.button
@ -447,7 +465,7 @@ class Weighing(Workflow, ModelSQL, ModelView):
InvoiceLine = pool.get('account.invoice.line')
Product = pool.get('product.product')
Company = pool.get('company.company')
context = Transaction().context
ContractProductPriceListTypePriceList = pool.get(
'agronomics.contract-product.price_list.type-product.price_list')
WeighingInvoiceLine = pool.get(
@ -456,6 +474,10 @@ class Weighing(Workflow, ModelSQL, ModelView):
type='wizard')
Move = pool.get('stock.move')
context = Transaction().context
company = Company(context['company'])
default_invoice_line_values = InvoiceLine.default_get(
InvoiceLine._fields.keys(), with_rec_name=False)
invoice_line = InvoiceLine(**default_invoice_line_values)
@ -465,7 +487,8 @@ class Weighing(Workflow, ModelSQL, ModelView):
to_recompute_products = []
for weighing in weighings:
cost_price = Decimal(0)
if weighing.beneficiaries:
if not weighing.is_maquila and weighing.beneficiaries:
for beneficiary in weighing.beneficiaries:
price_list = ContractProductPriceListTypePriceList.search([
('contract', '=', weighing.purchase_contract),
@ -477,9 +500,8 @@ class Weighing(Workflow, ModelSQL, ModelView):
invoice_line.type = 'line'
invoice_line.invoice_type = 'in'
invoice_line.party = beneficiary.party
invoice_line.currency = (
Company(context['company']).currency)
invoice_line.company = Company(context['company'])
invoice_line.currency = company.currency
invoice_line.company = company
invoice_line.description = ''
invoice_line.product = weighing.product_created
invoice_line.on_change_product()
@ -521,6 +543,8 @@ class Weighing(Workflow, ModelSQL, ModelView):
recompute_cost_price.start.from_ = default_values['from_']
recompute_cost_price.transition_recompute()
cls.save(weighings)
WeighingInvoiceLine.save(to_save)
Move.save(to_save_moves)