parent
d86b01104e
commit
5f780dc502
|
@ -13,6 +13,7 @@ def register():
|
|||
stock.StockCsvImport,
|
||||
shipment.ShipmentOutReturn,
|
||||
shipment.ShipmentIn,
|
||||
shipment.ShipmentInternal,
|
||||
module='stock_csv_import', type_='model')
|
||||
Pool.register(
|
||||
stock.CsvImport,
|
||||
|
|
|
@ -13,6 +13,8 @@ class Configuration(metaclass=PoolMeta):
|
|||
'Shipment out Return CSV Headers')
|
||||
shipment_in_csv_headers = fields.Char(
|
||||
'Shipment in CSV Headers')
|
||||
shipment_internal_csv_headers = fields.Char(
|
||||
'Shipment interal CSV Headers')
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
|
|
18
locale/es.po
18
locale/es.po
|
@ -78,6 +78,10 @@ msgctxt "selection:stock.shipment.csv_import.start,shipment_type:"
|
|||
msgid "Out return"
|
||||
msgstr "Devolución cliente"
|
||||
|
||||
msgctxt "selection:stock.shipment.csv_import.start,shipment_type:"
|
||||
msgid "Internal"
|
||||
msgstr "Interno"
|
||||
|
||||
msgctxt "model:ir.action,name:wizard_shipment_out_return_csv_import"
|
||||
msgid "Import CSV Shipment Out return"
|
||||
msgstr "Importar CSV albarán devolución de cliente"
|
||||
|
@ -94,6 +98,14 @@ msgctxt "model:ir.ui.menu,name:menu_wizard_shipment_in_csv_import"
|
|||
msgid "Import CSV Shipment In"
|
||||
msgstr "Importar CSV proveedor"
|
||||
|
||||
msgctxt "model:ir.action,name:wizard_shipment_internal_csv_import"
|
||||
msgid "Import CSV Shipment Internal"
|
||||
msgstr "Importar CSV albarán interno"
|
||||
|
||||
msgctxt "model:ir.ui.menu,name:menu_wizard_shipment_internal_csv_import"
|
||||
msgid "Import CSV Shipment Internal"
|
||||
msgstr "Importar CSV interno"
|
||||
|
||||
msgctxt "model:ir.ui.menu,name:menu_stock_csv_import"
|
||||
msgid "CSV Import"
|
||||
msgstr "Importaciones CSV"
|
||||
|
@ -116,4 +128,8 @@ msgstr "Albarán proveedor"
|
|||
|
||||
msgctxt "view:stock.configuration:"
|
||||
msgid "Shipment out return"
|
||||
msgstr "Albarán devolución cliente"
|
||||
msgstr "Albarán devolución cliente"
|
||||
|
||||
msgctxt "view:stock.configuration:"
|
||||
msgid "Shipment internal"
|
||||
msgstr "Albarán interno"
|
19
shipment.py
19
shipment.py
|
@ -5,7 +5,7 @@ from .stock import (ShipmentCSVMixin, ShipmentCSVProductMixin,
|
|||
ShipmentCSVLocationMixin)
|
||||
|
||||
__all__ = ['ShipmentOutReturn', 'ShipmentIn', 'ShipmentInProduct',
|
||||
'ShipmentOutReturnProduct']
|
||||
'ShipmentOutReturnProduct', 'ShipmentInternal']
|
||||
|
||||
|
||||
class ShipmentOutReturn(ShipmentCSVMixin, metaclass=PoolMeta):
|
||||
|
@ -90,3 +90,20 @@ class ShipmentInLocation(ShipmentCSVLocationMixin, metaclass=PoolMeta):
|
|||
'address': data['contact_address'].id
|
||||
if data['contact_address'] else None
|
||||
}
|
||||
|
||||
|
||||
class ShipmentInternal(ShipmentCSVMixin, metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.internal'
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls._csv_move_field = 'incoming_moves'
|
||||
|
||||
@classmethod
|
||||
def _get_csv_key(cls):
|
||||
return ('to_location', 'from_location', ) + super()._get_csv_key()
|
||||
|
||||
def _set_csv_move_locations(self, move):
|
||||
move.from_location = self.from_location
|
||||
move.to_location = self.to_location
|
||||
|
|
|
@ -20,5 +20,14 @@
|
|||
<menuitem id="menu_wizard_shipment_in_csv_import"
|
||||
sequence="40" parent="stock.menu_shipment_in_form"
|
||||
action="wizard_shipment_in_csv_import"/>
|
||||
|
||||
<!-- Wizard Shipment Internal CSV Import -->
|
||||
<record model="ir.action.wizard" id="wizard_shipment_internal_csv_import">
|
||||
<field name="name">Import CSV Shipment Internal</field>
|
||||
<field name="wiz_name">stock.shipment.csv_import</field>
|
||||
</record>
|
||||
<menuitem id="menu_wizard_shipment_internal_csv_import"
|
||||
sequence="40" parent="stock.menu_shipment_internal_form"
|
||||
action="wizard_shipment_internal_csv_import"/>
|
||||
</data>
|
||||
</tryton>
|
53
stock.py
53
stock.py
|
@ -59,27 +59,30 @@ class ShipmentCSVMixin(object):
|
|||
fieldname = splitted_field[0]
|
||||
else:
|
||||
fieldname = field_name
|
||||
if isinstance(Model._fields[fieldname], fields.Many2One):
|
||||
field = Model._fields[fieldname]
|
||||
relation = field.get_target().__name__
|
||||
RelModel = pool.get(relation)
|
||||
domain = cls._get_csv_field_extra_domain(field.name, data, row=row)
|
||||
if splitted_field:
|
||||
domain.append((".".join(splitted_field[1:]), '=', field_value))
|
||||
else:
|
||||
domain.append(('rec_name', '=', field_value))
|
||||
value = RelModel.search(domain)
|
||||
if user_error and field_value and not value:
|
||||
cls.raise_user_error('csv_relation_not_found', (
|
||||
Model.fields_get(fields_names=[fieldname]
|
||||
)[fieldname]['string'],
|
||||
field_value))
|
||||
return value[0] if value else None
|
||||
elif isinstance(Model._fields[fieldname], fields.Date):
|
||||
try:
|
||||
return datetime.strptime(field_value, "%Y-%m-%d").date()
|
||||
except ValueError:
|
||||
cls.raise_user_error('csv_date_format_error')
|
||||
if getattr(Model, fieldname, False):
|
||||
if isinstance(Model._fields[fieldname], fields.Many2One):
|
||||
field = Model._fields[fieldname]
|
||||
relation = field.get_target().__name__
|
||||
RelModel = pool.get(relation)
|
||||
domain = cls._get_csv_field_extra_domain(field.name, data,
|
||||
row=row)
|
||||
if splitted_field:
|
||||
domain.append((".".join(splitted_field[1:]), '=',
|
||||
field_value))
|
||||
else:
|
||||
domain.append(('rec_name', '=', field_value))
|
||||
value = RelModel.search(domain)
|
||||
if user_error and field_value and not value:
|
||||
cls.raise_user_error('csv_relation_not_found', (
|
||||
Model.fields_get(fields_names=[fieldname]
|
||||
)[fieldname]['string'],
|
||||
field_value))
|
||||
return value[0] if value else None
|
||||
elif isinstance(Model._fields[fieldname], fields.Date):
|
||||
try:
|
||||
return datetime.strptime(field_value, "%Y-%m-%d").date()
|
||||
except ValueError:
|
||||
cls.raise_user_error('csv_date_format_error')
|
||||
return field_value
|
||||
|
||||
@classmethod
|
||||
|
@ -369,7 +372,10 @@ class CsvImport(Wizard):
|
|||
'wizard_shipment_out_return_csv_import'):
|
||||
'stock.shipment.out.return',
|
||||
Modeldata.get_id('stock_csv_import',
|
||||
'wizard_shipment_in_csv_import'): 'stock.shipment.in'
|
||||
'wizard_shipment_in_csv_import'): 'stock.shipment.in',
|
||||
Modeldata.get_id('stock_csv_import',
|
||||
'wizard_shipment_internal_csv_import'):
|
||||
'stock.shipment.internal'
|
||||
}
|
||||
_type = actions.get(Transaction().context['action_id'], None)
|
||||
return {
|
||||
|
@ -414,7 +420,8 @@ class CsvImportStart(ModelView):
|
|||
show_type = fields.Boolean('Show type')
|
||||
shipment_type = fields.Selection([
|
||||
('stock.shipment.out.return', 'Out return'),
|
||||
('stock.shipment.in', 'In')
|
||||
('stock.shipment.in', 'In'),
|
||||
('stock.shipment.internal', 'Internal')
|
||||
], 'Shipment type', required=True,
|
||||
states={
|
||||
'invisible': Not(Bool(Eval('show_type')))
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
reference,effective_date,from_location,to_location,product,quantity
|
||||
Reference 1,2020-04-07,Storage 1,Storage 2,1,50
|
|
|
@ -0,0 +1,2 @@
|
|||
reference,effective_date,from_location,to_location,product,quantity
|
||||
Reference 1,2020-04-07,Storage Error,Storage 2,1,50
|
|
|
@ -0,0 +1,99 @@
|
|||
===========================================
|
||||
Stock Shipment Internal Csv Import Scenario
|
||||
===========================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> from proteus import Model, Wizard
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
>>> from trytond.modules.stock_csv_import.tests.tools import read_csv_file
|
||||
>>> import os
|
||||
>>> from trytond.modules.company.tests.tools import create_company, \
|
||||
... get_company
|
||||
>>> from decimal import Decimal
|
||||
|
||||
Install stock_csv_import::
|
||||
|
||||
>>> config = activate_modules('stock_csv_import')
|
||||
|
||||
Create company::
|
||||
|
||||
>>> _ = create_company()
|
||||
>>> company = get_company()
|
||||
|
||||
Create Configuration::
|
||||
|
||||
>>> Configuration = Model.get('stock.configuration')
|
||||
>>> config = Configuration()
|
||||
>>> config.shipment_internal_csv_headers = "reference,effective_date,from_location.name,to_location.name,incoming_moves.product.id,incoming_moves.quantity"
|
||||
>>> config.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 1'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.purchasable = True
|
||||
>>> template.list_price = Decimal('10')
|
||||
>>> template.cost_price = Decimal('5')
|
||||
>>> template.cost_price_method = 'fixed'
|
||||
>>> template.save()
|
||||
>>> product.template = template
|
||||
>>> product.save()
|
||||
|
||||
Create locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> sto_loc1 = Location(name='Storage 1')
|
||||
>>> sto_loc1.code = 'STO'
|
||||
>>> sto_loc1.type = 'storage'
|
||||
>>> sto_loc1.save()
|
||||
>>> sto_loc2 = Location(name='Storage 2')
|
||||
>>> sto_loc2.code = 'STO'
|
||||
>>> sto_loc2.type = 'storage'
|
||||
>>> sto_loc2.save()
|
||||
|
||||
CSV import wizard::
|
||||
|
||||
>>> ShipmentInternal = Model.get('stock.shipment.internal')
|
||||
>>> Data = Model.get('ir.model.data')
|
||||
>>> data, = Data.find([
|
||||
... ('module', '=', 'stock_csv_import'),
|
||||
... ('fs_id', '=', 'wizard_shipment_internal_csv_import')])
|
||||
>>> csv_import = Wizard('stock.shipment.csv_import', action={'id': data.db_id})
|
||||
>>> filename = os.path.join(os.path.dirname(__file__), 'internal.csv')
|
||||
>>> csv_import.form.csv_file = read_csv_file(filename)
|
||||
>>> csv_import.form.store_file = False
|
||||
>>> csv_import.execute('import_')
|
||||
>>> shipment, = ShipmentInternal.find([])
|
||||
>>> shipment.effective_date
|
||||
datetime.date(2020, 4, 7)
|
||||
>>> shipment.from_location == sto_loc1
|
||||
True
|
||||
>>> shipment.to_location == sto_loc2
|
||||
True
|
||||
>>> move, = shipment.moves
|
||||
>>> move.quantity
|
||||
50.0
|
||||
>>> move.product.name
|
||||
'Product 1'
|
||||
>>> move.from_location == shipment.from_location
|
||||
True
|
||||
>>> move.to_location == shipment.to_location
|
||||
True
|
||||
|
||||
CSV import wizard when location does not exist::
|
||||
|
||||
>>> csv_import = Wizard('stock.shipment.csv_import', action={'id': data.db_id})
|
||||
>>> filename = os.path.join(os.path.dirname(__file__), 'internal_error.csv')
|
||||
>>> csv_import.form.csv_file = read_csv_file(filename)
|
||||
>>> csv_import.execute('import_')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
trytond.exceptions.UserError: Cannot find a From Location record with value "Storage Error". -
|
|
@ -39,4 +39,9 @@ def suite():
|
|||
tearDown=doctest_teardown, encoding='utf-8',
|
||||
checker=doctest_checker,
|
||||
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||
suite.addTests(doctest.DocFileSuite(
|
||||
'scenario_shipment_internal_csv_import.rst',
|
||||
tearDown=doctest_teardown, encoding='utf-8',
|
||||
checker=doctest_checker,
|
||||
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||
return suite
|
||||
|
|
|
@ -8,5 +8,7 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="shipment_in_csv_headers" colspan="3"/>
|
||||
<label name="shipment_out_return_csv_headers" string="Shipment out return"/>
|
||||
<field name="shipment_out_return_csv_headers" colspan="3"/>
|
||||
<label name="shipment_internal_csv_headers" string="Shipment internal"/>
|
||||
<field name="shipment_internal_csv_headers" colspan="3"/>
|
||||
</xpath>
|
||||
</data>
|
Loading…
Reference in New Issue