Skip to content
Snippets Groups Projects
Commit 8328d2be authored by Cédric Krier's avatar Cédric Krier :atom:
Browse files

Initial commit

issue6436
review38321003
parents
No related branches found
No related tags found
No related merge requests found
image: python:all
env:
- POSTGRESQL_URI=postgresql://postgres@127.0.0.1:5432/
- MYSQL_URI=mysql://root@127.0.0.1:3306/
script:
- pip install tox
- tox -e "{py27,py33,py34,py35}-{sqlite,postgresql}" --skip-missing-interpreters
services:
- postgres
Copyright (C) 2017 Cédric Krier
Copyright (C) 2017 B2CK
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
INSTALL 0 → 100644
Installing trytond_stock_consignment
====================================
Prerequisites
-------------
* Python 2.7 or later (http://www.python.org/)
* trytond (http://www.tryton.org/)
* trytond_account_invoice (http://www.tryton.org/)
* trytond_account_invoice_line_standalone (http://www.tryton.org/)
* trytond_account_invoice_stock (http://www.tryton.org/)
* trytond_purchase (http://www.tryton.org/)
* trytond_sale (http://www.tryton.org/)
* trytond_stock (http://www.tryton.org/)
Installation
------------
Once you've downloaded and unpacked the trytond_stock_consignment source
release, enter the directory where the archive was unpacked, and run:
python setup.py install
Note that you may need administrator/root privileges for this step, as
this command will by default attempt to install module to the Python
site-packages directory on your system.
For advanced options, please refer to the easy_install and/or the distutils
documentation:
http://setuptools.readthedocs.io/en/latest/easy_install.html
http://docs.python.org/inst/inst.html
To use without installation, extract the archive into ``trytond/modules`` with
the directory name stock_consignment.
This diff is collapsed.
include INSTALL
include README
include COPYRIGHT
include CHANGELOG
include LICENSE
include tryton.cfg
include *.xml
include view/*.xml
include *.odt
include locale/*.po
include doc/*
include icons/*
include tests/*.rst
README 0 → 100644
trytond_stock_consignment
=========================
The stock_consignment module of the Tryton application platform.
Installing
----------
See INSTALL
Support
-------
If you encounter any problems with Tryton, please don't hesitate to ask
questions on the Tryton bug tracker, mailing list, wiki or IRC channel:
http://bugs.tryton.org/
http://groups.tryton.org/
http://wiki.tryton.org/
irc://irc.freenode.net/tryton
License
-------
See LICENSE
Copyright
---------
See COPYRIGHT
For more information please visit the Tryton web site:
http://www.tryton.org/
# 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.pool import Pool
from . import stock
from . import account
__all__ = ['register']
def register():
Pool.register(
stock.Location,
stock.LocationLeadTime,
stock.Move,
stock.ShipmentInternal,
stock.Inventory,
stock.OrderPoint,
account.InvoiceLine,
module='stock_consignment', type_='model')
# 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.pool import PoolMeta, Pool
__all__ = ['InvoiceLine']
class InvoiceLine:
__metaclass__ = PoolMeta
__name__ = 'account.invoice.line'
@property
def origin_name(self):
pool = Pool()
Move = pool.get('stock.move')
name = super(InvoiceLine, self).origin_name
if (isinstance(self.origin, Move)
and self.origin.shipment):
name = self.origin.shipment.rec_name
return name
@classmethod
def _get_origin(cls):
return super(InvoiceLine, cls)._get_origin() + ['stock.move']
Stock Consignment Module
########################
The stock consignment modules allow to manage consignment stock from supplier
or at customer warehouse.
The consignment stock from supplier is managed by creating a supplier location
under the company's warehouse storage. The location can be filled using an
Internal Shipment from the external supplier location. The products are used
also by using an Internal Shipment from the consignment location to a storage
location. In this case, a supplier invoice line is created for the supplier
defined on the location.
The consignment stock at customer warehouse is managed by creating a storage
location under the customer location. The location can be filled using an
Internal Shipment from a warehouse. It is possible to define a lead time
between the warehouse and the storage location. The products are used also by
using an Internal Shipment from the consignment location to a customer
location. In this case, a customer invoice line is created for the customer
defined on the location.
It is allowed to make inventory for those consignment locations.
A new field is added to Location:
- Consignment Party: The party invoiced when consignment is used.
setup.py 0 → 100644
#!/usr/bin/env python
# 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 setuptools import setup
import re
import os
import io
try:
from configparser import ConfigParser
except ImportError:
from ConfigParser import ConfigParser
def read(fname):
return io.open(
os.path.join(os.path.dirname(__file__), fname),
'r', encoding='utf-8').read()
def get_require_version(name):
if minor_version % 2:
require = '%s >= %s.%s.dev0, < %s.%s'
else:
require = '%s >= %s.%s, < %s.%s'
require %= (name, major_version, minor_version,
major_version, minor_version + 1)
return require
config = ConfigParser()
config.readfp(open('tryton.cfg'))
info = dict(config.items('tryton'))
for key in ('depends', 'extras_depend', 'xml'):
if key in info:
info[key] = info[key].strip().splitlines()
version = info.get('version', '0.0.1')
major_version, minor_version, _ = version.split('.', 2)
major_version = int(major_version)
minor_version = int(minor_version)
name = 'trytond_stock_consignment'
download_url = 'http://downloads.tryton.org/%s.%s/' % (
major_version, minor_version)
if minor_version % 2:
version = '%s.%s.dev0' % (major_version, minor_version)
download_url = (
'hg+http://hg.tryton.org/modules/%s#egg=%s-%s' % (
name[8:], name, version))
requires = []
for dep in info.get('depends', []):
if not re.match(r'(ir|res)(\W|$)', dep):
requires.append(get_require_version('trytond_%s' % dep))
requires.append(get_require_version('trytond'))
tests_require = [get_require_version('proteus')]
dependency_links = []
if minor_version % 2:
# Add development index for testing with proteus
dependency_links.append('https://trydevpi.tryton.org/')
setup(name=name,
version=version,
description='Tryton module to manage consignment stock',
long_description=read('README'),
author='Tryton',
author_email='issue_tracker@tryton.org',
url='http://www.tryton.org/',
download_url=download_url,
keywords='tryton stock consignment',
package_dir={'trytond.modules.stock_consignment': '.'},
packages=[
'trytond.modules.stock_consignment',
'trytond.modules.stock_consignment.tests',
],
package_data={
'trytond.modules.stock_consignment': (info.get('xml', [])
+ ['tryton.cfg', 'view/*.xml', 'locale/*.po', '*.odt',
'icons/*.svg', 'tests/*.rst']),
},
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Plugins',
'Framework :: Tryton',
'Intended Audience :: Developers',
'Intended Audience :: Financial and Insurance Industry',
'Intended Audience :: Legal Industry',
'Intended Audience :: Manufacturing',
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
'Natural Language :: Bulgarian',
'Natural Language :: Catalan',
'Natural Language :: Chinese (Simplified)',
'Natural Language :: Czech',
'Natural Language :: Dutch',
'Natural Language :: English',
'Natural Language :: French',
'Natural Language :: German',
'Natural Language :: Hungarian',
'Natural Language :: Italian',
'Natural Language :: Polish',
'Natural Language :: Portuguese (Brazilian)',
'Natural Language :: Russian',
'Natural Language :: Slovenian',
'Natural Language :: Spanish',
'Operating System :: OS Independent',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Office/Business',
],
license='GPL-3',
install_requires=requires,
dependency_links=dependency_links,
zip_safe=False,
entry_points="""
[trytond.modules]
stock_consignment = trytond.modules.stock_consignment
""",
test_suite='tests',
test_loader='trytond.test_loader:Loader',
tests_require=tests_require,
use_2to3=True,
convert_2to3_doctests=[
'tests/scenario_stock_consignment.rst',
],
)
stock.py 0 → 100644
# 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 decimal import Decimal
from functools import wraps
from trytond.model import ModelView, Workflow, fields
from trytond.transaction import Transaction
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval
__all__ = ['Location', 'LocationLeadTime',
'Move', 'ShipmentInternal', 'Inventory', 'OrderPoint']
class Location:
__metaclass__ = PoolMeta
__name__ = 'stock.location'
consignment_party = fields.Many2One(
'party.party', "Consignment Party",
states={
'invisible': ~Eval('type').in_(['supplier', 'storage']),
},
depends=['type'],
help="The party invoiced when consignment stock is used.")
@classmethod
def _parent_domain(cls):
domain = super(Location, cls)._parent_domain()
domain['supplier'].append('storage')
domain['storage'].append('customer')
return domain
class LocationLeadTime:
__metaclass__ = PoolMeta
__name__ = 'stock.location.lead_time'
@classmethod
def __setup__(cls):
super(LocationLeadTime, cls).__setup__()
cls.warehouse_to.domain = ['OR',
cls.warehouse_to.domain,
('type', '=', 'storage'),
]
def set_origin_consignment(func):
@wraps(func)
def wrapper(cls, moves):
pool = Pool()
InvoiceLine = pool.get('account.invoice.line')
lines = {}
for move in moves:
if not move.origin:
line = move.get_invoice_line_consignment()
if line:
lines[move] = line
if lines:
InvoiceLine.save(lines.values())
for move, line in lines.iteritems():
move.origin = line
cls.save(lines.keys())
return func(cls, moves)
return wrapper
def unset_origin_consignment(func):
@wraps(func)
def wrapper(cls, moves):
pool = Pool()
InvoiceLine = pool.get('account.invoice.line')
lines, to_save = [], []
for move in moves:
if (isinstance(move.origin, InvoiceLine)
and move.origin.origin == move):
lines.append(move.origin)
move.origin = None
to_save.append(move)
if lines:
InvoiceLine.delete(lines)
cls.save(to_save)
return func(cls, moves)
return wrapper
class Move:
__metaclass__ = PoolMeta
__name__ = 'stock.move'
@classmethod
def _get_origin(cls):
return super(Move, cls)._get_origin() + ['account.invoice.line']
@fields.depends('from_location')
def on_change_with_assignation_required(self, name=None):
required = super(Move, self).on_change_with_assignation_required(
name=name)
if self.from_location:
if (self.from_location.type == 'supplier'
and self.from_location.warehouse):
required = True
return required
def _get_tax_rule_pattern(self):
return {}
def get_invoice_line_consignment(self):
if (self.from_location.type == 'supplier'
and self.to_location.type == 'storage'
and self.from_location.consignment_party):
return self._get_supplier_invoice_line_consignment()
elif (self.from_location.type == 'storage'
and self.to_location.type == 'customer'
and self.from_location.consignment_party):
return self._get_customer_invoice_line_consignment()
def _get_supplier_invoice_line_consignment(self):
pool = Pool()
InvoiceLine = pool.get('account.invoice.line')
Product = pool.get('product.product')
ProductSupplier = pool.get('purchase.product_supplier')
with Transaction().set_context(
supplier=self.from_location.consignment_party.id):
pattern = ProductSupplier.get_pattern()
for product_supplier in self.product.product_suppliers:
if product_supplier.match(pattern):
currency = product_supplier.currency
break
else:
currency = self.company.currency
line = InvoiceLine()
line.invoice_type = 'in'
line.type = 'line'
line.company = self.company
line.party = self.from_location.consignment_party
line.currency = currency
line.product = self.product
line.description = self.product.name
line.quantity = self.quantity
line.unit = self.uom
line.account = self.product.account_expense_used
line.stock_moves = [self]
line.origin = self
taxes = []
pattern = self._get_tax_rule_pattern()
for tax in line.product.supplier_taxes_used:
if line.party.supplier_tax_rule:
tax_ids = line.party.supplier_tax_rule.apply(tax, pattern)
if tax_ids:
taxes.extend(tax_ids)
continue
taxes.append(tax.id)
if line.party.supplier_tax_rule:
tax_ids = line.party.supplier_tax_rule.apply(None, pattern)
if tax_ids:
taxes.extend(tax_ids)
line.taxes = taxes
with Transaction().set_context(
currency=line.currency.id,
supplier=line.party.id,
uom=line.unit,
taxes=[t.id for t in line.taxes]):
line.unit_price = Product.get_purchase_price(
[line.product], line.quantity)[line.product.id]
line.unit_price = line.unit_price.quantize(
Decimal(1) / 10 ** line.__class__.unit_price.digits[1])
return line
def _get_customer_invoice_line_consignment(self):
pool = Pool()
InvoiceLine = pool.get('account.invoice.line')
Product = pool.get('product.product')
line = InvoiceLine()
line.invoice_type = 'out'
line.type = 'line'
line.company = self.company
line.party = self.from_location.consignment_party
line.currency = self.company.currency
line.product = self.product
line.description = self.product.name
line.quantity = self.quantity
line.unit = self.uom
line.account = self.product.account_revenue_used
line.stock_moves = [self]
line.origin = self
taxes = []
pattern = self._get_tax_rule_pattern()
for tax in line.product.customer_taxes_used:
if line.party.customer_tax_rule:
tax_ids = line.party.customer_tax_rule.apply(tax, pattern)
if tax_ids:
taxes.extend(tax_ids)
continue
taxes.append(tax.id)
if line.party.customer_tax_rule:
tax_ids = line.party.customer_tax_rule.apply(None, pattern)
if tax_ids:
taxes.extend(tax_ids)
line.taxes = taxes
with Transaction().set_context(
currency=line.currency.id,
customer=line.party.id,
uom=line.unit,
taxes=[t.id for t in line.taxes]):
line.unit_price = Product.get_sale_price(
[line.product], line.quantity)[line.product.id]
line.unit_price = line.unit_price.quantize(
Decimal(1) / 10 ** line.__class__.unit_price.digits[1])
return line
@classmethod
@ModelView.button
@Workflow.transition('draft')
@unset_origin_consignment
def draft(cls, moves):
super(Move, cls).draft(moves)
@classmethod
@ModelView.button
@Workflow.transition('assigned')
@set_origin_consignment
def assign(cls, moves):
super(Move, cls).assign(moves)
@classmethod
@ModelView.button
@Workflow.transition('done')
@set_origin_consignment
def do(cls, moves):
super(Move, cls).do(moves)
@classmethod
@ModelView.button
@Workflow.transition('cancel')
@unset_origin_consignment
def cancel(cls, moves):
super(Move, cls).cancel(moves)
class ShipmentInternal:
__metaclass__ = PoolMeta
__name__ = 'stock.shipment.internal'
@classmethod
def __setup__(cls):
super(ShipmentInternal, cls).__setup__()
cls.from_location.domain = ['OR',
cls.from_location.domain,
('type', '=', 'supplier'),
]
cls.to_location.domain = ['OR',
cls.to_location.domain,
('type', 'in', ['supplier', 'customer']),
]
@fields.depends('to_location')
def on_change_with_planned_start_date(self, pattern=None):
if pattern is None:
pattern = {}
if self.to_location and not self.to_location.warehouse:
pattern.setdefault('location_to', self.to_location.id)
return super(ShipmentInternal, self).on_change_with_planned_start_date(
pattern=pattern)
class Inventory:
__metaclass__ = PoolMeta
__name__ = 'stock.inventory'
@classmethod
def __setup__(cls):
super(Inventory, cls).__setup__()
cls.location.domain = ['OR',
cls.location.domain,
('type', '=', 'supplier'),
]
class OrderPoint:
__metaclass__ = PoolMeta
__name__ = 'stock.order_point'
@classmethod
def __setup__(cls):
super(OrderPoint, cls).__setup__()
cls.provisioning_location.domain = ['OR',
cls.provisioning_location.domain,
('type', '=', 'supplier'),
]
<?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>
<record model="ir.ui.view" id="location_view_form">
<field name="model">stock.location</field>
<field name="inherit" ref="stock.location_view_form"/>
<field name="name">location_form</field>
</record>
</data>
</tryton>
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
try:
from trytond.modules.stock_consignment.tests.test_stock_consignment import suite
except ImportError:
from .test_stock_consignment import suite
__all__ = ['suite']
==========================
Stock Consignment Scenario
==========================
Imports::
>>> from decimal import Decimal
>>> from proteus import Model, Wizard
>>> from trytond.tests.tools import activate_modules
>>> from trytond.modules.company.tests.tools import create_company, \
... get_company
>>> from trytond.modules.account.tests.tools import create_chart, \
... get_accounts, create_tax
Install stock_consignment::
>>> config = activate_modules('stock_consignment')
Create company::
>>> _ = create_company()
>>> company = get_company()
Create chart of accounts::
>>> _ = create_chart(company)
>>> accounts = get_accounts(company)
>>> revenue = accounts['revenue']
>>> expense = accounts['expense']
Create tax::
>>> supplier_tax = create_tax(Decimal('.10'))
>>> supplier_tax.save()
>>> customer_tax = create_tax(Decimal('.10'))
>>> customer_tax.save()
Create parties::
>>> Party = Model.get('party.party')
>>> supplier = Party(name='Supplier')
>>> supplier.save()
>>> customer = Party(name='Customer')
>>> customer.save()
Get stock locations::
>>> Location = Model.get('stock.location')
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
>>> storage_loc, = Location.find([('code', '=', 'STO')])
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
>>> output_loc, = Location.find([('code', '=', 'OUT')])
Create supplier consignment location::
>>> supplier_consignment_loc = Location()
>>> supplier_consignment_loc.name = "Supplier Consignment"
>>> supplier_consignment_loc.type = 'supplier'
>>> supplier_consignment_loc.parent = storage_loc
>>> supplier_consignment_loc.consignment_party = supplier
>>> supplier_consignment_loc.save()
Create customer consignment location::
>>> customer_consignment_loc = Location()
>>> customer_consignment_loc.name = "Customer Consignment"
>>> customer_consignment_loc.type = 'storage'
>>> customer_consignment_loc.parent = customer_loc
>>> customer_consignment_loc.consignment_party = customer
>>> customer_consignment_loc.save()
Create product::
>>> ProductUom = Model.get('product.uom')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> ProductTemplate = Model.get('product.template')
>>> Product = Model.get('product.product')
>>> product = Product()
>>> template = ProductTemplate()
>>> template.name = 'product'
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.purchasable = True
>>> template.salable = True
>>> template.list_price = Decimal('10')
>>> template.cost_price = Decimal('5')
>>> template.cost_price_method = 'fixed'
>>> template.account_expense = expense
>>> template.account_revenue = revenue
>>> template.supplier_taxes.append(supplier_tax)
>>> template.customer_taxes.append(customer_tax)
>>> product_supplier = template.product_suppliers.new()
>>> product_supplier.party = supplier
>>> price = product_supplier.prices.new()
>>> price.quantity = 2
>>> price.unit_price = Decimal('4')
>>> template.save()
>>> product.template = template
>>> product.save()
Fill supplier consignment location::
>>> Shipment = Model.get('stock.shipment.internal')
>>> shipment = Shipment()
>>> shipment.from_location = supplier_loc
>>> shipment.to_location = supplier_consignment_loc
>>> move = shipment.moves.new()
>>> move.product = product
>>> move.quantity = 10
>>> move.from_location = supplier_loc
>>> move.to_location = supplier_consignment_loc
>>> shipment.click('wait')
>>> shipment.state
u'waiting'
>>> shipment.click('assign_try')
True
>>> shipment.state
u'assigned'
>>> shipment.click('done')
>>> shipment.state
u'done'
Use supplier consignment stock::
>>> shipment = Shipment()
>>> shipment.from_location = supplier_consignment_loc
>>> shipment.to_location = storage_loc
>>> move = shipment.moves.new()
>>> move.product = product
>>> move.quantity = 4
>>> move.from_location = supplier_consignment_loc
>>> move.to_location = storage_loc
>>> shipment.click('wait')
>>> shipment.state
u'waiting'
>>> shipment.click('assign_try')
True
>>> shipment.state
u'assigned'
>>> shipment.click('done')
>>> shipment.state
u'done'
Check supplier invoice line::
>>> InvoiceLine = Model.get('account.invoice.line')
>>> invoice_line, = InvoiceLine.find([('invoice_type', '=', 'in')])
>>> invoice_line.product == product
True
>>> invoice_line.quantity
4.0
>>> invoice_line.unit == unit
True
>>> invoice_line.unit_price
Decimal('4.0000')
>>> invoice_line.taxes == [supplier_tax]
True
>>> move, = shipment.moves
>>> move.origin == invoice_line
True
Use supplier consignment stock for shipment out::
>>> ShipmentOut = Model.get('stock.shipment.out')
>>> shipment_out = ShipmentOut()
>>> shipment_out.customer = customer
>>> shipment_out.warehouse = warehouse_loc
>>> move = shipment_out.outgoing_moves.new()
>>> move.product = product
>>> move.quantity = 3
>>> move.from_location = output_loc
>>> move.to_location = customer_loc
>>> shipment_out.click('wait')
>>> move, = shipment_out.inventory_moves
>>> move.from_location = supplier_consignment_loc
>>> shipment_out.click('assign_try')
True
>>> move, = shipment_out.inventory_moves
>>> isinstance(move.origin, InvoiceLine)
True
Fill customer consignment location::
>>> shipment = Shipment()
>>> shipment.from_location = storage_loc
>>> shipment.to_location = customer_consignment_loc
>>> move = shipment.moves.new()
>>> move.product = product
>>> move.quantity = 3
>>> move.from_location = storage_loc
>>> move.to_location = customer_consignment_loc
>>> shipment.click('wait')
>>> shipment.state
u'waiting'
>>> shipment.click('assign_try')
True
>>> shipment.state
u'assigned'
>>> shipment.click('done')
>>> shipment.state
u'done'
Use customer consignment stock::
>>> shipment = Shipment()
>>> shipment.from_location = customer_consignment_loc
>>> shipment.to_location = customer_loc
>>> move = shipment.moves.new()
>>> move.product = product
>>> move.quantity = 1
>>> move.from_location = customer_consignment_loc
>>> move.to_location = customer_loc
>>> shipment.click('wait')
>>> shipment.state
u'waiting'
>>> shipment.click('assign_try')
True
>>> shipment.state
u'assigned'
>>> shipment.click('done')
>>> shipment.state
u'done'
Check customer invoice line::
>>> invoice_line, = InvoiceLine.find([('invoice_type', '=', 'out')])
>>> invoice_line.product == product
True
>>> invoice_line.quantity
1.0
>>> invoice_line.unit == unit
True
>>> invoice_line.unit_price
Decimal('10.0000')
>>> invoice_line.taxes == [customer_tax]
True
>>> move, = shipment.moves
>>> move.origin == invoice_line
True
Cancel supplier consignment stock::
>>> shipment = Shipment()
>>> shipment.from_location = supplier_consignment_loc
>>> shipment.to_location = storage_loc
>>> move = shipment.moves.new()
>>> move.product = product
>>> move.quantity = 1
>>> move.from_location = supplier_consignment_loc
>>> move.to_location = storage_loc
>>> shipment.click('wait')
>>> shipment.state
u'waiting'
>>> shipment.click('assign_try')
True
>>> shipment.state
u'assigned'
>>> move, = shipment.moves
>>> bool(move.origin)
True
>>> shipment.click('cancel')
>>> shipment.state
u'cancel'
>>> move, = shipment.moves
>>> bool(move.origin)
False
# 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
from trytond.tests.test_tryton import ModuleTestCase
from trytond.tests.test_tryton import suite as test_suite
from trytond.tests.test_tryton import doctest_teardown
from trytond.tests.test_tryton import doctest_checker
class StockConsignmentTestCase(ModuleTestCase):
'Test Stock Consignment module'
module = 'stock_consignment'
def suite():
suite = test_suite()
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(
StockConsignmentTestCase))
suite.addTests(doctest.DocFileSuite(
'scenario_stock_consignment.rst',
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite
tox.ini 0 → 100644
[tox]
envlist = {py27,py33,py34,py35}-{sqlite,postgresql,mysql},pypy-{sqlite,postgresql}
[testenv]
commands = {envpython} setup.py test
deps =
{py27,py33,py34,py35}-postgresql: psycopg2 >= 2.5
pypy-postgresql: psycopg2cffi >= 2.5
mysql: MySQL-python
sqlite: sqlitebck
setenv =
sqlite: TRYTOND_DATABASE_URI={env:SQLITE_URI:sqlite://}
postgresql: TRYTOND_DATABASE_URI={env:POSTGRESQL_URI:postgresql://}
mysql: TRYTOND_DATABASE_URI={env:MYSQL_URI:mysql://}
sqlite: DB_NAME={env:SQLITE_NAME::memory:}
postgresql: DB_NAME={env:POSTGRESQL_NAME:test}
mysql: DB_NAME={env:MYSQL_NAME:test}
install_command = pip install --pre --find-links https://trydevpi.tryton.org/ {opts} {packages}
[tryton]
version=4.5.0
depends:
account_invoice
account_invoice_line_standalone
account_invoice_stock
ir
purchase
sale
stock
extras_depend:
stock_supply
xml:
stock.xml
<?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='address']" position="after">
<newline/>
<label name="consignment_party"/>
<field name="consignment_party"/>
</xpath>
</data>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment