Upgrade from 3.4 changes
This commit is contained in:
parent
0c478ae82b
commit
7c724bab46
|
@ -2,6 +2,18 @@
|
|||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
msgctxt "error:production:"
|
||||
msgid "The production \"%s\" has no incoming shipment."
|
||||
msgstr "La producció \"%s\" no té l'albarà d'entrada."
|
||||
|
||||
msgctxt "error:production:"
|
||||
msgid "The production \"%s\" has no the incoming shipment \"%s\" as done."
|
||||
msgstr "La producció \"%s\" no té l'albarà d'entrada \"%s\" en estat realitzat."
|
||||
|
||||
msgctxt "error:production:"
|
||||
msgid "The warehouse \"%s\" has no production location."
|
||||
msgstr "El magatzem \"%s\" no té una ubicació de producció."
|
||||
|
||||
msgctxt "field:party.party,production_warehouse:"
|
||||
msgid "Production Warehouse"
|
||||
msgstr "Magatzem producció"
|
||||
|
|
|
@ -2,6 +2,20 @@
|
|||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
msgctxt "error:production:"
|
||||
msgid "The production \"%s\" has no incoming shipment."
|
||||
msgstr "La producción \"%s\" no tiene el albarán de entrada."
|
||||
|
||||
msgctxt "error:production:"
|
||||
msgid "The production \"%s\" has no the incoming shipment \"%s\" as done."
|
||||
msgstr ""
|
||||
"La producción \"%s\" no tiene el albarán de entrada \"%s\" en estado "
|
||||
"realizado."
|
||||
|
||||
msgctxt "error:production:"
|
||||
msgid "The warehouse \"%s\" has no production location."
|
||||
msgstr "El almacén \"%s\" no tiene una ubicació de producción."
|
||||
|
||||
msgctxt "field:party.party,production_warehouse:"
|
||||
msgid "Production Warehouse"
|
||||
msgstr "Almacén producción"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# The COPYRIGHT file at the top level of this repository contains the full
|
||||
# copyright notices and license terms.
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.model import ModelView, Workflow, fields
|
||||
from trytond.model import ModelView, fields
|
||||
from trytond.pyson import Eval, Bool
|
||||
|
||||
__all__ = ['Party', 'PurchaseRequest', 'BOM', 'Production', 'Purchase']
|
||||
|
@ -42,6 +42,7 @@ class BOM:
|
|||
('type', '=', 'service'),
|
||||
])
|
||||
|
||||
# TODO: Subcontract cost must be added to the cost of the production
|
||||
|
||||
class Production:
|
||||
__name__ = 'production'
|
||||
|
@ -76,6 +77,16 @@ class Production:
|
|||
'icon': 'tryton-go-home',
|
||||
}
|
||||
})
|
||||
cls._error_messages.update({
|
||||
'no_subcontract_warehouse': 'The party "%s" has no production '
|
||||
'location.',
|
||||
'no_warehouse_production_location': 'The warehouse "%s" has '
|
||||
'no production location.',
|
||||
'no_incoming_shipment': 'The production "%s" has no incoming '
|
||||
'shipment.',
|
||||
'no_incoming_shipment_done': ('The production "%s" has no the '
|
||||
'incoming shipment "%s" as done.'),
|
||||
})
|
||||
|
||||
def get_supplier(self, name):
|
||||
return (self.purchase_request.party.id if self.purchase_request and
|
||||
|
@ -107,18 +118,16 @@ class Production:
|
|||
production.save()
|
||||
|
||||
def on_change_product(self):
|
||||
res = super(Production, self).on_change_product()
|
||||
super(Production, self).on_change_product()
|
||||
if self.bom:
|
||||
res['subcontract_product'] = (self.bom.subcontract_product.id if
|
||||
self.subcontract_product = (self.bom.subcontract_product.id if
|
||||
self.bom.subcontract_product else None)
|
||||
return res
|
||||
|
||||
def on_change_bom(self):
|
||||
res = super(Production, self).on_change_bom()
|
||||
super(Production, self).on_change_bom()
|
||||
if self.bom:
|
||||
res['subcontract_product'] = (self.bom.subcontract_product.id if
|
||||
self.subcontract_product = (self.bom.subcontract_product.id if
|
||||
self.bom.subcontract_product else None)
|
||||
return res
|
||||
|
||||
def _get_purchase_request(self):
|
||||
PurchaseRequest = Pool().get('purchase.request')
|
||||
|
@ -139,13 +148,21 @@ class Production:
|
|||
for production in productions:
|
||||
if not (production.purchase_request and
|
||||
production.purchase_request.purchase and
|
||||
production.purchase_request.purchase.state == 'processing'):
|
||||
production.purchase_request.purchase.state in
|
||||
('processing', 'done')):
|
||||
continue
|
||||
if production.destination_warehouse:
|
||||
continue
|
||||
subcontract_warehouse = production._get_subcontract_warehouse()
|
||||
if not subcontract_warehouse:
|
||||
cls.raise_user_error('no_subcontract_warehouse', (
|
||||
production.purchase_request.party.rec_name, ))
|
||||
production.destination_warehouse = production.warehouse
|
||||
production.warehouse = subcontract_warehouse
|
||||
if not production.warehouse.production_location:
|
||||
cls.raise_user_error('no_warehouse_production_location', (
|
||||
production.warehouse.rec_name, ))
|
||||
production.location = production.warehouse.production_location
|
||||
|
||||
from_location = production.warehouse.storage_location
|
||||
to_location = production.destination_warehouse.storage_location
|
||||
|
@ -210,10 +227,24 @@ class Production:
|
|||
# ShipmentIn where there is no direct linke between stock moves but are
|
||||
# calculated by product and quantities. See _sync_inventory_to_outgoing in
|
||||
# stock/shipment.py.
|
||||
@classmethod
|
||||
def _sync_outputs_to_shipment(cls, productions):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def run(cls, productions):
|
||||
for p in productions:
|
||||
if p.purchase_request:
|
||||
if not p.incoming_shipment:
|
||||
cls.raise_user_error('no_incoming_shipment', (
|
||||
p.code,))
|
||||
if not p.incoming_shipment.state == 'done':
|
||||
cls.raise_user_error('no_incoming_shipment_done', (
|
||||
p.code, p.incoming_shipment.rec_name,))
|
||||
|
||||
super(Production, cls).run(productions)
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('done')
|
||||
def done(cls, productions):
|
||||
InternalShipment = Pool().get('stock.shipment.internal')
|
||||
super(Production, cls).done(productions)
|
||||
|
|
|
@ -1,33 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="party_view_form">
|
||||
<field name="model">party.party</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit" ref="party.party_view_form"/>
|
||||
<field name="name">party_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="production_view_form">
|
||||
<field name="model">production</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit" ref="production.production_view_form"/>
|
||||
<field name="name">production_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="production_view_list">
|
||||
<field name="model">production</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="inherit" ref="production.production_view_list"/>
|
||||
<field name="name">production_list</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="bom_view_form">
|
||||
<field name="model">production.bom</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit" ref="production.bom_view_form"/>
|
||||
<field name="name">bom_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="bom_view_list">
|
||||
<field name="model">production.bom</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="inherit" ref="production.bom_view_list"/>
|
||||
<field name="name">bom_list</field>
|
||||
</record>
|
||||
|
|
|
@ -12,6 +12,12 @@ Imports::
|
|||
>>> from dateutil.relativedelta import relativedelta
|
||||
>>> from decimal import Decimal
|
||||
>>> from proteus import config, Model, Wizard
|
||||
>>> from trytond.modules.company.tests.tools import create_company, \
|
||||
... get_company
|
||||
>>> from trytond.modules.account.tests.tools import create_fiscalyear, \
|
||||
... create_chart, get_accounts, create_tax
|
||||
>>> from trytond.modules.account_invoice.tests.tools import \
|
||||
... set_fiscalyear_invoice_sequences
|
||||
>>> today = datetime.date.today()
|
||||
>>> yesterday = today - relativedelta(days=1)
|
||||
|
||||
|
@ -22,42 +28,51 @@ Create database::
|
|||
|
||||
Install production Module::
|
||||
|
||||
>>> Module = Model.get('ir.module.module')
|
||||
>>> Module = Model.get('ir.module')
|
||||
>>> modules = Module.find([('name', '=', 'production_subcontract')])
|
||||
>>> Module.install([x.id for x in modules], config.context)
|
||||
>>> Wizard('ir.module.module.install_upgrade').execute('upgrade')
|
||||
>>> Wizard('ir.module.install_upgrade').execute('upgrade')
|
||||
|
||||
Create company::
|
||||
|
||||
>>> Currency = Model.get('currency.currency')
|
||||
>>> CurrencyRate = Model.get('currency.currency.rate')
|
||||
>>> Company = Model.get('company.company')
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> company_config = Wizard('company.company.config')
|
||||
>>> company_config.execute('company')
|
||||
>>> company = company_config.form
|
||||
>>> party = Party(name='Dunder Mifflin')
|
||||
>>> party.save()
|
||||
>>> company.party = party
|
||||
>>> currencies = Currency.find([('code', '=', 'USD')])
|
||||
>>> if not currencies:
|
||||
... currency = Currency(name='Euro', symbol=u'$', code='USD',
|
||||
... rounding=Decimal('0.01'), mon_grouping='[3, 3, 0]',
|
||||
... mon_decimal_point=',')
|
||||
... currency.save()
|
||||
... CurrencyRate(date=today + relativedelta(month=1, day=1),
|
||||
... rate=Decimal('1.0'), currency=currency).save()
|
||||
... else:
|
||||
... currency, = currencies
|
||||
>>> company.currency = currency
|
||||
>>> company_config.execute('add')
|
||||
>>> company, = Company.find()
|
||||
>>> _ = create_company()
|
||||
>>> company = get_company()
|
||||
|
||||
Reload the context::
|
||||
|
||||
>>> User = Model.get('res.user')
|
||||
>>> config._context = User.get_preferences(True, config.context)
|
||||
|
||||
Create fiscal year::
|
||||
|
||||
>>> fiscalyear = set_fiscalyear_invoice_sequences(
|
||||
... create_fiscalyear(company))
|
||||
>>> fiscalyear.click('create_period')
|
||||
|
||||
Create chart of accounts::
|
||||
|
||||
>>> _ = create_chart(company)
|
||||
>>> accounts = get_accounts(company)
|
||||
>>> revenue = accounts['revenue']
|
||||
>>> expense = accounts['expense']
|
||||
>>> cash = accounts['cash']
|
||||
|
||||
>>> Journal = Model.get('account.journal')
|
||||
>>> cash_journal, = Journal.find([('type', '=', 'cash')])
|
||||
>>> cash_journal.credit_account = cash
|
||||
>>> cash_journal.debit_account = cash
|
||||
>>> cash_journal.save()
|
||||
|
||||
Create payment term::
|
||||
|
||||
>>> PaymentTerm = Model.get('account.invoice.payment_term')
|
||||
>>> payment_term = PaymentTerm(name='Term')
|
||||
>>> line = payment_term.lines.new(type='percent', ratio=Decimal('.5'))
|
||||
>>> delta = line.relativedeltas.new(days=20)
|
||||
>>> line = payment_term.lines.new(type='remainder')
|
||||
>>> delta = line.relativedeltas.new(days=40)
|
||||
>>> payment_term.save()
|
||||
|
||||
Create supplier warehouse::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
|
@ -68,10 +83,10 @@ Create supplier warehouse::
|
|||
>>> supplier_output = Location(name='Supplier Output', type='storage')
|
||||
>>> supplier_output.save()
|
||||
>>> supplier_production = Location(name='Supplier Production',
|
||||
... type='storage')
|
||||
... type='production')
|
||||
>>> supplier_production.save()
|
||||
>>> supplier_warehouse = Location()
|
||||
>>> supplier_warehouse.type = 'warhouse'
|
||||
>>> supplier_warehouse.type = 'warehouse'
|
||||
>>> supplier_warehouse.name = 'Supplier Warehouse'
|
||||
>>> supplier_warehouse.storage_location = supplier_storage
|
||||
>>> supplier_warehouse.input_location = supplier_input
|
||||
|
@ -84,6 +99,7 @@ Create supplier::
|
|||
>>> Party = Model.get('party.party')
|
||||
>>> party = Party(name='Supplier')
|
||||
>>> party.production_warehouse = supplier_warehouse
|
||||
>>> party.save()
|
||||
|
||||
Create product::
|
||||
|
||||
|
@ -135,6 +151,9 @@ Create Subcontract Product::
|
|||
>>> stemplate.name = 'Subcontract'
|
||||
>>> stemplate.default_uom = unit
|
||||
>>> stemplate.type = 'service'
|
||||
>>> stemplate.purchasable = True
|
||||
>>> stemplate.account_expense = expense
|
||||
>>> stemplate.account_revenue = revenue
|
||||
>>> stemplate.list_price = Decimal(0)
|
||||
>>> stemplate.cost_price = Decimal(100)
|
||||
>>> stemplate.save()
|
||||
|
@ -168,10 +187,11 @@ Create Bill of Material::
|
|||
|
||||
Create an Inventory::
|
||||
|
||||
>>> warehouse, = Location.find(['code', '=', 'WH'])
|
||||
>>> Inventory = Model.get('stock.inventory')
|
||||
>>> InventoryLine = Model.get('stock.inventory.line')
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> storage = supplier_warehouse.storage_location
|
||||
>>> storage = warehouse.storage_location
|
||||
>>> inventory = Inventory()
|
||||
>>> inventory.location = storage
|
||||
>>> inventory_line1 = InventoryLine()
|
||||
|
@ -187,9 +207,30 @@ Create an Inventory::
|
|||
>>> inventory.state
|
||||
u'done'
|
||||
|
||||
Create a Supplier Inventory::
|
||||
|
||||
>>> storage = supplier_warehouse.storage_location
|
||||
>>> inventory = Inventory()
|
||||
>>> inventory.location = storage
|
||||
>>> inventory_line1 = InventoryLine()
|
||||
>>> inventory.lines.append(inventory_line1)
|
||||
>>> inventory_line1.product = component1
|
||||
>>> inventory_line1.quantity = 20
|
||||
>>> inventory_line2 = InventoryLine()
|
||||
>>> inventory.lines.append(inventory_line2)
|
||||
>>> inventory_line2.product = component2
|
||||
>>> inventory_line2.quantity = 6
|
||||
>>> inventory_line3 = InventoryLine()
|
||||
>>> inventory.lines.append(inventory_line3)
|
||||
>>> inventory_line3.product = product
|
||||
>>> inventory_line3.quantity = 2
|
||||
>>> inventory.save()
|
||||
>>> Inventory.confirm([inventory.id], config.context)
|
||||
>>> inventory.state
|
||||
u'done'
|
||||
|
||||
Make a production::
|
||||
|
||||
>>> warehouse = Location.find(['code', '=', 'WH'])
|
||||
>>> Production = Model.get('production')
|
||||
>>> production = Production()
|
||||
>>> production.warehouse = warehouse
|
||||
|
@ -202,7 +243,7 @@ Make a production::
|
|||
>>> output.quantity == 2
|
||||
True
|
||||
>>> production.cost
|
||||
Decimal('25.0')
|
||||
Decimal('25.0000')
|
||||
>>> production.save()
|
||||
>>> Production.wait([production.id], config.context)
|
||||
>>> production.state
|
||||
|
@ -225,43 +266,73 @@ Make a production::
|
|||
u'done'
|
||||
>>> output.effective_date == production.effective_date
|
||||
True
|
||||
>>> config._context['locations'] = [storage.id]
|
||||
>>> config._context['locations'] = [warehouse.id]
|
||||
>>> product.reload()
|
||||
>>> product.quantity == 2
|
||||
True
|
||||
|
||||
Make a production with effective date yesterday::
|
||||
Make a subcontract production::
|
||||
|
||||
>>> Production = Model.get('production')
|
||||
>>> Purchase = Model.get('purchase.purchase')
|
||||
>>> Internal = Model.get('stock.shipment.internal')
|
||||
>>> production = Production()
|
||||
>>> production.effective_date = yesterday
|
||||
>>> production.warehouse = warehouse
|
||||
>>> production.product = product
|
||||
>>> production.bom = bom
|
||||
>>> production.quantity = 2
|
||||
>>> production.subcontract_product == subcontract
|
||||
>>> production.click('wait')
|
||||
>>> production.click('create_purchase_request')
|
||||
|
||||
Process purchase request::
|
||||
|
||||
>>> sorted([i.quantity for i in production.inputs]) == [10, 300]
|
||||
True
|
||||
>>> output, = production.outputs
|
||||
>>> output.quantity == 2
|
||||
True
|
||||
>>> production.cost
|
||||
Decimal('25.0000')
|
||||
>>> production.subcontract_product = subcontract
|
||||
>>> production.save()
|
||||
>>> Production.wait([production.id], config.context)
|
||||
>>> production.reload()
|
||||
>>> production.state
|
||||
u'waiting'
|
||||
>>> Production.create_purchase_request([production.id], config.context)
|
||||
>>> production.reload()
|
||||
>>> purchase_request = production.purchase_request
|
||||
>>> create_purchase = Wizard('purchase.request.create_purchase',
|
||||
... [purchase_request])
|
||||
>>> create_purchase.form.party = party
|
||||
>>> create_purchase.execute('start')
|
||||
>>> purchase_request.reload()
|
||||
>>> purchase = purchase_request.purchase
|
||||
>>> purchase.click('quotation')
|
||||
>>> purchase.click('confirm')
|
||||
>>> purchase.click('process')
|
||||
>>> purchase.payment_term = payment_term
|
||||
>>> purchase.save()
|
||||
>>> Purchase.quote([purchase.id], config.context)
|
||||
>>> purchase.reload()
|
||||
>>> purchase.state
|
||||
u'quotation'
|
||||
>>> Purchase.confirm([purchase.id], config.context)
|
||||
>>> purchase.reload()
|
||||
>>> purchase.state
|
||||
u'confirmed'
|
||||
>>> Purchase.process([purchase.id], config.context)
|
||||
>>> purchase.reload()
|
||||
>>> purchase.state
|
||||
u'done'
|
||||
>>> production.reload()
|
||||
>>> production.warehouse = supplier_warehouse
|
||||
>>> production.destination_warehouse = warehouse
|
||||
>>> shipment = production.incoming_shipment
|
||||
|
||||
Process production::
|
||||
|
||||
>>> production.incoming_shipment.id
|
||||
1
|
||||
>>> internal = production.incoming_shipment
|
||||
>>> Internal.wait([internal.id], config.context)
|
||||
>>> internal.reload()
|
||||
>>> internal.state
|
||||
u'waiting'
|
||||
>>> Internal.assign_try([internal.id], config.context)
|
||||
True
|
||||
>>> Internal.done([internal.id], config.context)
|
||||
>>> internal.reload()
|
||||
>>> internal.state
|
||||
u'done'
|
||||
>>> Production.assign_try([production.id], config.context)
|
||||
True
|
||||
>>> production.click('run')
|
||||
>>> Production.run([production.id], config.context)
|
||||
>>> production.reload()
|
||||
>>> shipment.reload()
|
||||
>>> shipment.state = 'reserved'
|
||||
>>> production.state
|
||||
u'running'
|
|
@ -1,32 +1,24 @@
|
|||
#!/usr/bin/env python
|
||||
# The COPYRIGHT file at the top level of this repository contains the full
|
||||
# copyright notices and license terms.
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
import unittest
|
||||
import doctest
|
||||
import trytond.tests.test_tryton
|
||||
from trytond.tests.test_tryton import test_view, test_depends
|
||||
from trytond.tests.test_tryton import ModuleTestCase
|
||||
from trytond.tests.test_tryton import doctest_setup, doctest_teardown
|
||||
from trytond.tests.test_tryton import doctest_checker
|
||||
|
||||
|
||||
class TestCase(unittest.TestCase):
|
||||
'Test module'
|
||||
|
||||
def setUp(self):
|
||||
trytond.tests.test_tryton.install_module('production_subcontract')
|
||||
|
||||
def test0005views(self):
|
||||
'Test views'
|
||||
test_view('production_subcontract')
|
||||
|
||||
def test0006depends(self):
|
||||
'Test depends'
|
||||
test_depends()
|
||||
class ProductionSubcontractTestCase(ModuleTestCase):
|
||||
'Test Production Subcontract module'
|
||||
module = 'production_subcontract'
|
||||
|
||||
|
||||
def suite():
|
||||
suite = trytond.tests.test_tryton.suite()
|
||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCase))
|
||||
suite.addTests(doctest.DocFileSuite('scenario_production.rst',
|
||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(
|
||||
ProductionSubcontractTestCase))
|
||||
suite.addTests(doctest.DocFileSuite('scenario_production_subcontract.rst',
|
||||
setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8',
|
||||
checker=doctest_checker,
|
||||
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||
return suite
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[tryton]
|
||||
version=4.1.0
|
||||
version=3.4.0
|
||||
depends:
|
||||
production
|
||||
stock_supply
|
||||
|
|
Loading…
Reference in New Issue