Upgrade from 3.4 changes

This commit is contained in:
Raimon Esteve 2016-07-01 15:38:52 +02:00
parent 0c478ae82b
commit 7c724bab46
7 changed files with 203 additions and 88 deletions

View File

@ -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ó"

View File

@ -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"

View File

@ -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)

View File

@ -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>

View File

@ -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'

View File

@ -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

View File

@ -1,5 +1,5 @@
[tryton]
version=4.1.0
version=3.4.0
depends:
production
stock_supply