Move code in right files following guide lines
This commit is contained in:
+2
-1
@@ -3,9 +3,10 @@
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .purchase import *
|
||||
from .product import *
|
||||
from .stock import *
|
||||
from .configuration import *
|
||||
from .invoice import *
|
||||
from .stock import *
|
||||
|
||||
|
||||
def register():
|
||||
|
||||
+276
@@ -0,0 +1,276 @@
|
||||
#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 datetime
|
||||
from sql import Literal
|
||||
from sql.aggregate import Count
|
||||
|
||||
from trytond.model import ModelView, ModelSQL, fields
|
||||
from trytond.pyson import Eval, If
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.transaction import Transaction
|
||||
from trytond import backend
|
||||
|
||||
__all__ = ['Template', 'Product', 'ProductSupplier', 'ProductSupplierPrice']
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
||||
class Template:
|
||||
__name__ = "product.template"
|
||||
purchasable = fields.Boolean('Purchasable', states={
|
||||
'readonly': ~Eval('active', True),
|
||||
}, depends=['active'])
|
||||
product_suppliers = fields.One2Many('purchase.product_supplier',
|
||||
'product', 'Suppliers', states={
|
||||
'readonly': ~Eval('active', True),
|
||||
'invisible': (~Eval('purchasable', False)
|
||||
| ~Eval('context', {}).get('company', 0)),
|
||||
}, depends=['active', 'purchasable'])
|
||||
purchase_uom = fields.Many2One('product.uom', 'Purchase UOM', states={
|
||||
'readonly': ~Eval('active'),
|
||||
'invisible': ~Eval('purchasable'),
|
||||
'required': Eval('purchasable', False),
|
||||
},
|
||||
domain=[('category', '=', Eval('default_uom_category'))],
|
||||
on_change_with=['default_uom', 'purchase_uom', 'purchasable'],
|
||||
depends=['active', 'purchasable', 'default_uom_category'])
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(Template, cls).__setup__()
|
||||
cls._error_messages.update({
|
||||
'change_purchase_uom': ('Purchase prices are based '
|
||||
'on the purchase uom, are you sure to change it?'),
|
||||
})
|
||||
required = ~Eval('account_category') & Eval('purchasable', False)
|
||||
if not cls.account_expense.states.get('required'):
|
||||
cls.account_expense.states['required'] = required
|
||||
else:
|
||||
cls.account_expense.states['required'] = (
|
||||
cls.account_expense.states['required'] | required)
|
||||
if 'account_category' not in cls.account_expense.depends:
|
||||
cls.account_expense.depends.append('account_category')
|
||||
if 'purchasable' not in cls.account_expense.depends:
|
||||
cls.account_expense.depends.append('purchasable')
|
||||
|
||||
def on_change_with_purchase_uom(self):
|
||||
if self.default_uom:
|
||||
if self.purchase_uom:
|
||||
if self.default_uom.category == self.purchase_uom.category:
|
||||
return self.purchase_uom.id
|
||||
else:
|
||||
return self.default_uom.id
|
||||
else:
|
||||
return self.default_uom.id
|
||||
|
||||
@classmethod
|
||||
def write(cls, templates, vals):
|
||||
if vals.get("purchase_uom"):
|
||||
for template in templates:
|
||||
if not template.purchase_uom:
|
||||
continue
|
||||
if template.purchase_uom.id == vals["purchase_uom"]:
|
||||
continue
|
||||
for product in template.products:
|
||||
if not product.product_suppliers:
|
||||
continue
|
||||
cls.raise_user_warning(
|
||||
'%s@product_template' % template.id,
|
||||
'change_purchase_uom')
|
||||
super(Template, cls).write(templates, vals)
|
||||
|
||||
|
||||
class Product:
|
||||
__name__ = 'product.product'
|
||||
|
||||
@classmethod
|
||||
def get_purchase_price(cls, products, quantity=0):
|
||||
'''
|
||||
Return purchase price for product ids.
|
||||
The context that can have as keys:
|
||||
uom: the unit of measure
|
||||
supplier: the supplier party id
|
||||
currency: the currency id for the returned price
|
||||
'''
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
User = pool.get('res.user')
|
||||
Currency = pool.get('currency.currency')
|
||||
Date = pool.get('ir.date')
|
||||
|
||||
today = Date.today()
|
||||
res = {}
|
||||
|
||||
uom = None
|
||||
if Transaction().context.get('uom'):
|
||||
uom = Uom(Transaction().context['uom'])
|
||||
|
||||
currency = None
|
||||
if Transaction().context.get('currency'):
|
||||
currency = Currency(Transaction().context['currency'])
|
||||
|
||||
user = User(Transaction().user)
|
||||
|
||||
for product in products:
|
||||
res[product.id] = product.cost_price
|
||||
default_uom = product.default_uom
|
||||
default_currency = (user.company.currency if user.company
|
||||
else None)
|
||||
if not uom:
|
||||
uom = default_uom
|
||||
if (Transaction().context.get('supplier')
|
||||
and product.product_suppliers):
|
||||
supplier_id = Transaction().context['supplier']
|
||||
for product_supplier in product.product_suppliers:
|
||||
if product_supplier.party.id == supplier_id:
|
||||
for price in product_supplier.prices:
|
||||
if Uom.compute_qty(product.purchase_uom,
|
||||
price.quantity, uom) <= quantity:
|
||||
res[product.id] = price.unit_price
|
||||
default_uom = product.purchase_uom
|
||||
default_currency = product_supplier.currency
|
||||
break
|
||||
res[product.id] = Uom.compute_price(default_uom, res[product.id],
|
||||
uom)
|
||||
if currency and default_currency:
|
||||
date = Transaction().context.get('purchase_date') or today
|
||||
with Transaction().set_context(date=date):
|
||||
res[product.id] = Currency.compute(default_currency,
|
||||
res[product.id], currency, round=False)
|
||||
return res
|
||||
|
||||
|
||||
class ProductSupplier(ModelSQL, ModelView):
|
||||
'Product Supplier'
|
||||
__name__ = 'purchase.product_supplier'
|
||||
product = fields.Many2One('product.template', 'Product', required=True,
|
||||
ondelete='CASCADE', select=True)
|
||||
party = fields.Many2One('party.party', 'Supplier', required=True,
|
||||
ondelete='CASCADE', select=True, on_change=['party'])
|
||||
name = fields.Char('Name', size=None, translate=True, select=True)
|
||||
code = fields.Char('Code', size=None, select=True)
|
||||
sequence = fields.Integer('Sequence')
|
||||
prices = fields.One2Many('purchase.product_supplier.price',
|
||||
'product_supplier', 'Prices')
|
||||
company = fields.Many2One('company.company', 'Company', required=True,
|
||||
ondelete='CASCADE', select=True,
|
||||
domain=[
|
||||
('id', If(Eval('context', {}).contains('company'), '=', '!='),
|
||||
Eval('context', {}).get('company', 0)),
|
||||
])
|
||||
delivery_time = fields.Integer('Delivery Time', help="In number of days")
|
||||
currency = fields.Many2One('currency.currency', 'Currency', required=True,
|
||||
ondelete='RESTRICT')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ProductSupplier, cls).__setup__()
|
||||
cls._order.insert(0, ('sequence', 'ASC'))
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
TableHandler = backend.get('TableHandler')
|
||||
cursor = Transaction().cursor
|
||||
table = TableHandler(cursor, cls, module_name)
|
||||
sql_table = cls.__table__()
|
||||
|
||||
# Migration from 2.2 new field currency
|
||||
created_currency = table.column_exist('currency')
|
||||
|
||||
super(ProductSupplier, cls).__register__(module_name)
|
||||
|
||||
# Migration from 2.2 fill currency
|
||||
if not created_currency:
|
||||
Company = Pool().get('company.company')
|
||||
company = Company.__table__()
|
||||
limit = cursor.IN_MAX
|
||||
cursor.execute(*sql_table.select(Count(sql_table.id)))
|
||||
product_supplier_count, = cursor.fetchone()
|
||||
for offset in range(0, product_supplier_count, limit):
|
||||
cursor.execute(*sql_table.join(company,
|
||||
condition=sql_table.company == company.id
|
||||
).select(sql_table.id, company.currency,
|
||||
order_by=sql_table.id,
|
||||
limit=limit, offset=offset))
|
||||
for product_supplier_id, currency_id in cursor.fetchall():
|
||||
cursor.execute(*sql_table.update(
|
||||
columns=[sql_table.currency],
|
||||
values=[currency_id],
|
||||
where=sql_table.id == product_supplier_id))
|
||||
|
||||
# Migration from 2.4: drop required on sequence
|
||||
table.not_null_action('sequence', action='remove')
|
||||
|
||||
# Migration from 2.6: drop required on delivery_time
|
||||
table.not_null_action('delivery_time', action='remove')
|
||||
|
||||
@staticmethod
|
||||
def order_sequence(tables):
|
||||
table, _ = tables[None]
|
||||
return [table.sequence == None, table.sequence]
|
||||
|
||||
@staticmethod
|
||||
def default_company():
|
||||
return Transaction().context.get('company')
|
||||
|
||||
@staticmethod
|
||||
def default_currency():
|
||||
Company = Pool().get('company.company')
|
||||
if Transaction().context.get('company'):
|
||||
company = Company(Transaction().context['company'])
|
||||
return company.currency.id
|
||||
|
||||
def on_change_party(self):
|
||||
cursor = Transaction().cursor
|
||||
changes = {
|
||||
'currency': self.default_currency(),
|
||||
}
|
||||
if self.party:
|
||||
table = self.__table__()
|
||||
cursor.execute(*table.select(table.currency,
|
||||
where=table.party == self.party.id,
|
||||
group_by=table.currency,
|
||||
order_by=Count(Literal(1)).desc))
|
||||
row = cursor.fetchone()
|
||||
if row:
|
||||
changes['currency'], = row
|
||||
return changes
|
||||
|
||||
def compute_supply_date(self, date=None):
|
||||
'''
|
||||
Compute the supply date for the Product Supplier at the given date
|
||||
'''
|
||||
Date = Pool().get('ir.date')
|
||||
|
||||
if not date:
|
||||
date = Date.today()
|
||||
if self.delivery_time is None:
|
||||
return datetime.date.max
|
||||
return date + datetime.timedelta(self.delivery_time)
|
||||
|
||||
def compute_purchase_date(self, date):
|
||||
'''
|
||||
Compute the purchase date for the Product Supplier at the given date
|
||||
'''
|
||||
Date = Pool().get('ir.date')
|
||||
|
||||
if self.delivery_time is None:
|
||||
return Date.today()
|
||||
return date - datetime.timedelta(self.delivery_time)
|
||||
|
||||
|
||||
class ProductSupplierPrice(ModelSQL, ModelView):
|
||||
'Product Supplier Price'
|
||||
__name__ = 'purchase.product_supplier.price'
|
||||
product_supplier = fields.Many2One('purchase.product_supplier',
|
||||
'Supplier', required=True, ondelete='CASCADE')
|
||||
quantity = fields.Float('Quantity', required=True, help='Minimal quantity')
|
||||
unit_price = fields.Numeric('Unit Price', required=True, digits=(16, 4))
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ProductSupplierPrice, cls).__setup__()
|
||||
cls._order.insert(0, ('quantity', 'ASC'))
|
||||
|
||||
@staticmethod
|
||||
def default_quantity():
|
||||
return 0.0
|
||||
+3
-544
@@ -6,7 +6,6 @@ from decimal import Decimal
|
||||
from sql import Table, Literal
|
||||
from sql.functions import Overlay, Position
|
||||
from sql.aggregate import Count
|
||||
from sql.operators import Concat
|
||||
|
||||
from trytond.model import Workflow, ModelView, ModelSQL, fields
|
||||
from trytond.modules.company import CompanyReport
|
||||
@@ -19,12 +18,9 @@ from trytond.pool import Pool, PoolMeta
|
||||
|
||||
__all__ = ['Purchase', 'PurchaseInvoice', 'PurchaseIgnoredInvoice',
|
||||
'PurchaseRecreadtedInvoice', 'PurchaseLine', 'PurchaseLineTax',
|
||||
'PurchaseLineIgnoredMove',
|
||||
'PurchaseLineRecreatedMove', 'PurchaseReport', 'Template', 'Product',
|
||||
'ProductSupplier', 'ProductSupplierPrice', 'ShipmentIn',
|
||||
'ShipmentInReturn', 'Move', 'OpenSupplier', 'HandleShipmentExceptionAsk',
|
||||
'HandleShipmentException', 'HandleInvoiceExceptionAsk',
|
||||
'HandleInvoiceException']
|
||||
'PurchaseLineIgnoredMove', 'PurchaseLineRecreatedMove', 'PurchaseReport',
|
||||
'OpenSupplier', 'HandleShipmentExceptionAsk', 'HandleShipmentException',
|
||||
'HandleInvoiceExceptionAsk', 'HandleInvoiceException']
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
_STATES = {
|
||||
@@ -1320,543 +1316,6 @@ class PurchaseReport(CompanyReport):
|
||||
__name__ = 'purchase.purchase'
|
||||
|
||||
|
||||
class Template:
|
||||
__name__ = "product.template"
|
||||
purchasable = fields.Boolean('Purchasable', states={
|
||||
'readonly': ~Eval('active', True),
|
||||
}, depends=['active'])
|
||||
product_suppliers = fields.One2Many('purchase.product_supplier',
|
||||
'product', 'Suppliers', states={
|
||||
'readonly': ~Eval('active', True),
|
||||
'invisible': (~Eval('purchasable', False)
|
||||
| ~Eval('context', {}).get('company', 0)),
|
||||
}, depends=['active', 'purchasable'])
|
||||
purchase_uom = fields.Many2One('product.uom', 'Purchase UOM', states={
|
||||
'readonly': ~Eval('active'),
|
||||
'invisible': ~Eval('purchasable'),
|
||||
'required': Eval('purchasable', False),
|
||||
},
|
||||
domain=[('category', '=', Eval('default_uom_category'))],
|
||||
on_change_with=['default_uom', 'purchase_uom', 'purchasable'],
|
||||
depends=['active', 'purchasable', 'default_uom_category'])
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(Template, cls).__setup__()
|
||||
cls._error_messages.update({
|
||||
'change_purchase_uom': ('Purchase prices are based '
|
||||
'on the purchase uom, are you sure to change it?'),
|
||||
})
|
||||
required = ~Eval('account_category') & Eval('purchasable', False)
|
||||
if not cls.account_expense.states.get('required'):
|
||||
cls.account_expense.states['required'] = required
|
||||
else:
|
||||
cls.account_expense.states['required'] = (
|
||||
cls.account_expense.states['required'] | required)
|
||||
if 'account_category' not in cls.account_expense.depends:
|
||||
cls.account_expense.depends.append('account_category')
|
||||
if 'purchasable' not in cls.account_expense.depends:
|
||||
cls.account_expense.depends.append('purchasable')
|
||||
|
||||
def on_change_with_purchase_uom(self):
|
||||
if self.default_uom:
|
||||
if self.purchase_uom:
|
||||
if self.default_uom.category == self.purchase_uom.category:
|
||||
return self.purchase_uom.id
|
||||
else:
|
||||
return self.default_uom.id
|
||||
else:
|
||||
return self.default_uom.id
|
||||
|
||||
@classmethod
|
||||
def write(cls, templates, vals):
|
||||
if vals.get("purchase_uom"):
|
||||
for template in templates:
|
||||
if not template.purchase_uom:
|
||||
continue
|
||||
if template.purchase_uom.id == vals["purchase_uom"]:
|
||||
continue
|
||||
for product in template.products:
|
||||
if not product.product_suppliers:
|
||||
continue
|
||||
cls.raise_user_warning(
|
||||
'%s@product_template' % template.id,
|
||||
'change_purchase_uom')
|
||||
super(Template, cls).write(templates, vals)
|
||||
|
||||
|
||||
class Product:
|
||||
__name__ = 'product.product'
|
||||
|
||||
@classmethod
|
||||
def get_purchase_price(cls, products, quantity=0):
|
||||
'''
|
||||
Return purchase price for product ids.
|
||||
The context that can have as keys:
|
||||
uom: the unit of measure
|
||||
supplier: the supplier party id
|
||||
currency: the currency id for the returned price
|
||||
'''
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
User = pool.get('res.user')
|
||||
Currency = pool.get('currency.currency')
|
||||
Date = pool.get('ir.date')
|
||||
|
||||
today = Date.today()
|
||||
res = {}
|
||||
|
||||
uom = None
|
||||
if Transaction().context.get('uom'):
|
||||
uom = Uom(Transaction().context['uom'])
|
||||
|
||||
currency = None
|
||||
if Transaction().context.get('currency'):
|
||||
currency = Currency(Transaction().context['currency'])
|
||||
|
||||
user = User(Transaction().user)
|
||||
|
||||
for product in products:
|
||||
res[product.id] = product.cost_price
|
||||
default_uom = product.default_uom
|
||||
default_currency = (user.company.currency if user.company
|
||||
else None)
|
||||
if not uom:
|
||||
uom = default_uom
|
||||
if (Transaction().context.get('supplier')
|
||||
and product.product_suppliers):
|
||||
supplier_id = Transaction().context['supplier']
|
||||
for product_supplier in product.product_suppliers:
|
||||
if product_supplier.party.id == supplier_id:
|
||||
for price in product_supplier.prices:
|
||||
if Uom.compute_qty(product.purchase_uom,
|
||||
price.quantity, uom) <= quantity:
|
||||
res[product.id] = price.unit_price
|
||||
default_uom = product.purchase_uom
|
||||
default_currency = product_supplier.currency
|
||||
break
|
||||
res[product.id] = Uom.compute_price(default_uom, res[product.id],
|
||||
uom)
|
||||
if currency and default_currency:
|
||||
date = Transaction().context.get('purchase_date') or today
|
||||
with Transaction().set_context(date=date):
|
||||
res[product.id] = Currency.compute(default_currency,
|
||||
res[product.id], currency, round=False)
|
||||
return res
|
||||
|
||||
|
||||
class ProductSupplier(ModelSQL, ModelView):
|
||||
'Product Supplier'
|
||||
__name__ = 'purchase.product_supplier'
|
||||
product = fields.Many2One('product.template', 'Product', required=True,
|
||||
ondelete='CASCADE', select=True)
|
||||
party = fields.Many2One('party.party', 'Supplier', required=True,
|
||||
ondelete='CASCADE', select=True, on_change=['party'])
|
||||
name = fields.Char('Name', size=None, translate=True, select=True)
|
||||
code = fields.Char('Code', size=None, select=True)
|
||||
sequence = fields.Integer('Sequence')
|
||||
prices = fields.One2Many('purchase.product_supplier.price',
|
||||
'product_supplier', 'Prices')
|
||||
company = fields.Many2One('company.company', 'Company', required=True,
|
||||
ondelete='CASCADE', select=True,
|
||||
domain=[
|
||||
('id', If(Eval('context', {}).contains('company'), '=', '!='),
|
||||
Eval('context', {}).get('company', 0)),
|
||||
])
|
||||
delivery_time = fields.Integer('Delivery Time', help="In number of days")
|
||||
currency = fields.Many2One('currency.currency', 'Currency', required=True,
|
||||
ondelete='RESTRICT')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ProductSupplier, cls).__setup__()
|
||||
cls._order.insert(0, ('sequence', 'ASC'))
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
TableHandler = backend.get('TableHandler')
|
||||
cursor = Transaction().cursor
|
||||
table = TableHandler(cursor, cls, module_name)
|
||||
sql_table = cls.__table__()
|
||||
|
||||
# Migration from 2.2 new field currency
|
||||
created_currency = table.column_exist('currency')
|
||||
|
||||
super(ProductSupplier, cls).__register__(module_name)
|
||||
|
||||
# Migration from 2.2 fill currency
|
||||
if not created_currency:
|
||||
Company = Pool().get('company.company')
|
||||
company = Company.__table__()
|
||||
limit = cursor.IN_MAX
|
||||
cursor.execute(*sql_table.select(Count(sql_table.id)))
|
||||
product_supplier_count, = cursor.fetchone()
|
||||
for offset in range(0, product_supplier_count, limit):
|
||||
cursor.execute(*sql_table.join(company,
|
||||
condition=sql_table.company == company.id
|
||||
).select(sql_table.id, company.currency,
|
||||
order_by=sql_table.id,
|
||||
limit=limit, offset=offset))
|
||||
for product_supplier_id, currency_id in cursor.fetchall():
|
||||
cursor.execute(*sql_table.update(
|
||||
columns=[sql_table.currency],
|
||||
values=[currency_id],
|
||||
where=sql_table.id == product_supplier_id))
|
||||
|
||||
# Migration from 2.4: drop required on sequence
|
||||
table.not_null_action('sequence', action='remove')
|
||||
|
||||
# Migration from 2.6: drop required on delivery_time
|
||||
table.not_null_action('delivery_time', action='remove')
|
||||
|
||||
@staticmethod
|
||||
def order_sequence(tables):
|
||||
table, _ = tables[None]
|
||||
return [table.sequence == None, table.sequence]
|
||||
|
||||
@staticmethod
|
||||
def default_company():
|
||||
return Transaction().context.get('company')
|
||||
|
||||
@staticmethod
|
||||
def default_currency():
|
||||
Company = Pool().get('company.company')
|
||||
if Transaction().context.get('company'):
|
||||
company = Company(Transaction().context['company'])
|
||||
return company.currency.id
|
||||
|
||||
def on_change_party(self):
|
||||
cursor = Transaction().cursor
|
||||
changes = {
|
||||
'currency': self.default_currency(),
|
||||
}
|
||||
if self.party:
|
||||
table = self.__table__()
|
||||
cursor.execute(*table.select(table.currency,
|
||||
where=table.party == self.party.id,
|
||||
group_by=table.currency,
|
||||
order_by=Count(Literal(1)).desc))
|
||||
row = cursor.fetchone()
|
||||
if row:
|
||||
changes['currency'], = row
|
||||
return changes
|
||||
|
||||
def compute_supply_date(self, date=None):
|
||||
'''
|
||||
Compute the supply date for the Product Supplier at the given date
|
||||
'''
|
||||
Date = Pool().get('ir.date')
|
||||
|
||||
if not date:
|
||||
date = Date.today()
|
||||
if self.delivery_time is None:
|
||||
return datetime.date.max
|
||||
return date + datetime.timedelta(self.delivery_time)
|
||||
|
||||
def compute_purchase_date(self, date):
|
||||
'''
|
||||
Compute the purchase date for the Product Supplier at the given date
|
||||
'''
|
||||
Date = Pool().get('ir.date')
|
||||
|
||||
if self.delivery_time is None:
|
||||
return Date.today()
|
||||
return date - datetime.timedelta(self.delivery_time)
|
||||
|
||||
|
||||
class ProductSupplierPrice(ModelSQL, ModelView):
|
||||
'Product Supplier Price'
|
||||
__name__ = 'purchase.product_supplier.price'
|
||||
product_supplier = fields.Many2One('purchase.product_supplier',
|
||||
'Supplier', required=True, ondelete='CASCADE')
|
||||
quantity = fields.Float('Quantity', required=True, help='Minimal quantity')
|
||||
unit_price = fields.Numeric('Unit Price', required=True, digits=(16, 4))
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ProductSupplierPrice, cls).__setup__()
|
||||
cls._order.insert(0, ('quantity', 'ASC'))
|
||||
|
||||
@staticmethod
|
||||
def default_quantity():
|
||||
return 0.0
|
||||
|
||||
|
||||
class ShipmentIn:
|
||||
__name__ = 'stock.shipment.in'
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ShipmentIn, cls).__setup__()
|
||||
add_remove = [
|
||||
('supplier', '=', Eval('supplier')),
|
||||
]
|
||||
if not cls.incoming_moves.add_remove:
|
||||
cls.incoming_moves.add_remove = add_remove
|
||||
else:
|
||||
cls.incoming_moves.add_remove = [
|
||||
add_remove,
|
||||
cls.incoming_moves.add_remove,
|
||||
]
|
||||
if 'supplier' not in cls.incoming_moves.depends:
|
||||
cls.incoming_moves.depends.append('supplier')
|
||||
|
||||
cls._error_messages.update({
|
||||
'reset_move': ('You cannot reset to draft move "%s" because '
|
||||
'it was generated by a purchase.'),
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def write(cls, shipments, vals):
|
||||
pool = Pool()
|
||||
Purchase = pool.get('purchase.purchase')
|
||||
PurchaseLine = pool.get('purchase.line')
|
||||
|
||||
super(ShipmentIn, cls).write(shipments, vals)
|
||||
|
||||
if 'state' in vals and vals['state'] in ('received', 'cancel'):
|
||||
purchases = []
|
||||
move_ids = []
|
||||
for shipment in shipments:
|
||||
move_ids.extend([x.id for x in shipment.incoming_moves])
|
||||
|
||||
purchase_lines = PurchaseLine.search([
|
||||
('moves', 'in', move_ids),
|
||||
])
|
||||
if purchase_lines:
|
||||
for purchase_line in purchase_lines:
|
||||
if purchase_line.purchase not in purchases:
|
||||
purchases.append(purchase_line.purchase)
|
||||
|
||||
with Transaction().set_user(0, set_context=True):
|
||||
purchases = Purchase.browse([p.id for p in purchases])
|
||||
Purchase.process(purchases)
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('draft')
|
||||
def draft(cls, shipments):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
for shipment in shipments:
|
||||
for move in shipment.incoming_moves:
|
||||
if (move.state == 'cancel'
|
||||
and isinstance(move.origin, PurchaseLine)):
|
||||
cls.raise_user_error('reset_move', (move.rec_name,))
|
||||
|
||||
return super(ShipmentIn, cls).draft(shipments)
|
||||
|
||||
|
||||
class ShipmentInReturn:
|
||||
__name__ = 'stock.shipment.in.return'
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ShipmentInReturn, cls).__setup__()
|
||||
cls._error_messages.update({
|
||||
'reset_move': ('You cannot reset to draft a move generated '
|
||||
'by a purchase.'),
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def write(cls, shipments, vals):
|
||||
pool = Pool()
|
||||
Purchase = pool.get('purchase.purchase')
|
||||
PurchaseLine = pool.get('purchase.line')
|
||||
|
||||
super(ShipmentInReturn, cls).write(shipments, vals)
|
||||
|
||||
if 'state' in vals and vals['state'] == 'done':
|
||||
move_ids = []
|
||||
for shipment in shipments:
|
||||
move_ids.extend([x.id for x in shipment.moves])
|
||||
|
||||
purchase_lines = PurchaseLine.search([
|
||||
('moves', 'in', move_ids),
|
||||
])
|
||||
purchases = set()
|
||||
if purchase_lines:
|
||||
for purchase_line in purchase_lines:
|
||||
purchases.add(purchase_line.purchase)
|
||||
|
||||
with Transaction().set_user(0, set_context=True):
|
||||
purchases = Purchase.browse([p.id for p in purchases])
|
||||
Purchase.process(purchases)
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('draft')
|
||||
def draft(cls, shipments):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
for shipment in shipments:
|
||||
for move in shipment.moves:
|
||||
if (move.state == 'cancel'
|
||||
and isinstance(move.origin, PurchaseLine)):
|
||||
cls.raise_user_error('reset_move')
|
||||
|
||||
return super(ShipmentInReturn, cls).draft(shipments)
|
||||
|
||||
|
||||
class Move(ModelSQL, ModelView):
|
||||
__name__ = 'stock.move'
|
||||
purchase = fields.Function(fields.Many2One('purchase.purchase', 'Purchase',
|
||||
states={
|
||||
'invisible': ~Eval('purchase_visible', False),
|
||||
},
|
||||
depends=['purchase_visible']), 'get_purchase',
|
||||
searcher='search_purchase')
|
||||
purchase_quantity = fields.Function(fields.Float('Purchase Quantity',
|
||||
digits=(16, Eval('unit_digits', 2)),
|
||||
states={
|
||||
'invisible': ~Eval('purchase_visible', False),
|
||||
},
|
||||
depends=['purchase_visible', 'unit_digits']),
|
||||
'get_purchase_fields')
|
||||
purchase_unit = fields.Function(fields.Many2One('product.uom',
|
||||
'Purchase Unit', states={
|
||||
'invisible': ~Eval('purchase_visible', False),
|
||||
}, depends=['purchase_visible']), 'get_purchase_fields')
|
||||
purchase_unit_digits = fields.Function(fields.Integer(
|
||||
'Purchase Unit Digits'), 'get_purchase_fields')
|
||||
purchase_unit_price = fields.Function(fields.Numeric('Purchase Unit Price',
|
||||
digits=(16, 4), states={
|
||||
'invisible': ~Eval('purchase_visible', False),
|
||||
}, depends=['purchase_visible']), 'get_purchase_fields')
|
||||
purchase_currency = fields.Function(fields.Many2One('currency.currency',
|
||||
'Purchase Currency', states={
|
||||
'invisible': ~Eval('purchase_visible', False),
|
||||
}, depends=['purchase_visible']), 'get_purchase_fields')
|
||||
purchase_visible = fields.Function(fields.Boolean('Purchase Visible',
|
||||
on_change_with=['from_location']), 'on_change_with_purchase_visible')
|
||||
supplier = fields.Function(fields.Many2One('party.party', 'Supplier'),
|
||||
'get_supplier', searcher='search_supplier')
|
||||
purchase_exception_state = fields.Function(fields.Selection([
|
||||
('', ''),
|
||||
('ignored', 'Ignored'),
|
||||
('recreated', 'Recreated'),
|
||||
], 'Exception State'), 'get_purchase_exception_state')
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
TableHandler = backend.get('TableHandler')
|
||||
cursor = Transaction().cursor
|
||||
sql_table = cls.__table__()
|
||||
|
||||
super(Move, cls).__register__(module_name)
|
||||
|
||||
table = TableHandler(cursor, cls, module_name)
|
||||
|
||||
# Migration from 2.6: remove purchase_line
|
||||
if table.column_exist('purchase_line'):
|
||||
cursor.execute(*sql_table.update(
|
||||
columns=[sql_table.origin],
|
||||
values=[Concat('purchase.line,', sql_table.purchase_line)],
|
||||
where=sql_table.purchase_line != None))
|
||||
table.drop_column('purchase_line')
|
||||
|
||||
@classmethod
|
||||
def _get_origin(cls):
|
||||
models = super(Move, cls)._get_origin()
|
||||
models.append('purchase.line')
|
||||
return models
|
||||
|
||||
def get_purchase(self, name):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
if isinstance(self.origin, PurchaseLine):
|
||||
return self.origin.purchase.id
|
||||
|
||||
@classmethod
|
||||
def search_purchase(cls, name, clause):
|
||||
return [('origin.' + name,) + tuple(clause[1:]) + ('purchase.line',)]
|
||||
|
||||
def get_purchase_exception_state(self, name):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
if not isinstance(self.origin, PurchaseLine):
|
||||
return ''
|
||||
if self in self.origin.moves_recreated:
|
||||
return 'recreated'
|
||||
if self in self.origin.moves_ignored:
|
||||
return 'ignored'
|
||||
|
||||
def get_purchase_fields(self, name):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
if isinstance(self.origin, PurchaseLine):
|
||||
if name[9:] == 'currency':
|
||||
return self.origin.purchase.currency.id
|
||||
elif name[9:] in ('quantity', 'unit_digits', 'unit_price'):
|
||||
return getattr(self.origin, name[9:])
|
||||
else:
|
||||
return getattr(self.origin, name[9:]).id
|
||||
else:
|
||||
if name[9:] == 'quantity':
|
||||
return 0.0
|
||||
elif name[9:] == 'unit_digits':
|
||||
return 2
|
||||
|
||||
def on_change_with_purchase_visible(self, name=None):
|
||||
if self.from_location:
|
||||
if self.from_location.type == 'supplier':
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_supplier(self, name):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
if isinstance(self.origin, PurchaseLine):
|
||||
return self.origin.purchase.party.id
|
||||
|
||||
@property
|
||||
def origin_name(self):
|
||||
pool = Pool()
|
||||
PurchaseLine = pool.get('purchase.line')
|
||||
name = super(Move, self).origin_name
|
||||
if isinstance(self.origin, PurchaseLine):
|
||||
name = self.origin.purchase.rec_name
|
||||
return name
|
||||
|
||||
@classmethod
|
||||
def search_supplier(cls, name, clause):
|
||||
return [('origin.purchase.party',) + tuple(clause[1:]) +
|
||||
('purchase.line',)]
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('cancel')
|
||||
def cancel(cls, moves):
|
||||
pool = Pool()
|
||||
Purchase = pool.get('purchase.purchase')
|
||||
PurchaseLine = pool.get('purchase.line')
|
||||
|
||||
super(Move, cls).cancel(moves)
|
||||
purchase_lines = PurchaseLine.search([
|
||||
('moves', 'in', [m.id for m in moves]),
|
||||
])
|
||||
if purchase_lines:
|
||||
purchase_ids = list(set(l.purchase.id for l in purchase_lines))
|
||||
with Transaction().set_user(0, set_context=True):
|
||||
purchases = Purchase.browse(purchase_ids)
|
||||
Purchase.process(purchases)
|
||||
|
||||
@classmethod
|
||||
def delete(cls, moves):
|
||||
pool = Pool()
|
||||
Purchase = pool.get('purchase.purchase')
|
||||
PurchaseLine = pool.get('purchase.line')
|
||||
|
||||
purchases = set()
|
||||
purchase_lines = PurchaseLine.search([
|
||||
('moves', 'in', [m.id for m in moves]),
|
||||
])
|
||||
|
||||
super(Move, cls).delete(moves)
|
||||
|
||||
if purchase_lines:
|
||||
for purchase_line in purchase_lines:
|
||||
purchases.add(purchase_line.purchase)
|
||||
if purchases:
|
||||
with Transaction().set_user(0, set_context=True):
|
||||
purchases = Purchase.browse([p.id for p in purchases])
|
||||
Purchase.process(purchases)
|
||||
|
||||
|
||||
class OpenSupplier(Wizard):
|
||||
'Open Suppliers'
|
||||
__name__ = 'purchase.open_supplier'
|
||||
|
||||
@@ -1,13 +1,294 @@
|
||||
#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 datetime
|
||||
from sql.operators import Concat
|
||||
|
||||
from trytond.model import Workflow, ModelView, fields
|
||||
from trytond.pyson import Eval
|
||||
from trytond.wizard import Wizard
|
||||
from trytond.pool import Pool
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pyson import PYSONDecoder, PYSONEncoder
|
||||
from trytond import backend
|
||||
|
||||
__all__ = ['OpenProductQuantitiesByWarehouse']
|
||||
__all__ = ['ShipmentIn', 'ShipmentInReturn', 'Move',
|
||||
'OpenProductQuantitiesByWarehouse']
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
||||
class ShipmentIn:
|
||||
__name__ = 'stock.shipment.in'
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ShipmentIn, cls).__setup__()
|
||||
add_remove = [
|
||||
('supplier', '=', Eval('supplier')),
|
||||
]
|
||||
if not cls.incoming_moves.add_remove:
|
||||
cls.incoming_moves.add_remove = add_remove
|
||||
else:
|
||||
cls.incoming_moves.add_remove = [
|
||||
add_remove,
|
||||
cls.incoming_moves.add_remove,
|
||||
]
|
||||
if 'supplier' not in cls.incoming_moves.depends:
|
||||
cls.incoming_moves.depends.append('supplier')
|
||||
|
||||
cls._error_messages.update({
|
||||
'reset_move': ('You cannot reset to draft move "%s" because '
|
||||
'it was generated by a purchase.'),
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def write(cls, shipments, vals):
|
||||
pool = Pool()
|
||||
Purchase = pool.get('purchase.purchase')
|
||||
PurchaseLine = pool.get('purchase.line')
|
||||
|
||||
super(ShipmentIn, cls).write(shipments, vals)
|
||||
|
||||
if 'state' in vals and vals['state'] in ('received', 'cancel'):
|
||||
purchases = []
|
||||
move_ids = []
|
||||
for shipment in shipments:
|
||||
move_ids.extend([x.id for x in shipment.incoming_moves])
|
||||
|
||||
purchase_lines = PurchaseLine.search([
|
||||
('moves', 'in', move_ids),
|
||||
])
|
||||
if purchase_lines:
|
||||
for purchase_line in purchase_lines:
|
||||
if purchase_line.purchase not in purchases:
|
||||
purchases.append(purchase_line.purchase)
|
||||
|
||||
with Transaction().set_user(0, set_context=True):
|
||||
purchases = Purchase.browse([p.id for p in purchases])
|
||||
Purchase.process(purchases)
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('draft')
|
||||
def draft(cls, shipments):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
for shipment in shipments:
|
||||
for move in shipment.incoming_moves:
|
||||
if (move.state == 'cancel'
|
||||
and isinstance(move.origin, PurchaseLine)):
|
||||
cls.raise_user_error('reset_move', (move.rec_name,))
|
||||
|
||||
return super(ShipmentIn, cls).draft(shipments)
|
||||
|
||||
|
||||
class ShipmentInReturn:
|
||||
__name__ = 'stock.shipment.in.return'
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ShipmentInReturn, cls).__setup__()
|
||||
cls._error_messages.update({
|
||||
'reset_move': ('You cannot reset to draft a move generated '
|
||||
'by a purchase.'),
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def write(cls, shipments, vals):
|
||||
pool = Pool()
|
||||
Purchase = pool.get('purchase.purchase')
|
||||
PurchaseLine = pool.get('purchase.line')
|
||||
|
||||
super(ShipmentInReturn, cls).write(shipments, vals)
|
||||
|
||||
if 'state' in vals and vals['state'] == 'done':
|
||||
move_ids = []
|
||||
for shipment in shipments:
|
||||
move_ids.extend([x.id for x in shipment.moves])
|
||||
|
||||
purchase_lines = PurchaseLine.search([
|
||||
('moves', 'in', move_ids),
|
||||
])
|
||||
purchases = set()
|
||||
if purchase_lines:
|
||||
for purchase_line in purchase_lines:
|
||||
purchases.add(purchase_line.purchase)
|
||||
|
||||
with Transaction().set_user(0, set_context=True):
|
||||
purchases = Purchase.browse([p.id for p in purchases])
|
||||
Purchase.process(purchases)
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('draft')
|
||||
def draft(cls, shipments):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
for shipment in shipments:
|
||||
for move in shipment.moves:
|
||||
if (move.state == 'cancel'
|
||||
and isinstance(move.origin, PurchaseLine)):
|
||||
cls.raise_user_error('reset_move')
|
||||
|
||||
return super(ShipmentInReturn, cls).draft(shipments)
|
||||
|
||||
|
||||
class Move:
|
||||
__name__ = 'stock.move'
|
||||
purchase = fields.Function(fields.Many2One('purchase.purchase', 'Purchase',
|
||||
states={
|
||||
'invisible': ~Eval('purchase_visible', False),
|
||||
},
|
||||
depends=['purchase_visible']), 'get_purchase',
|
||||
searcher='search_purchase')
|
||||
purchase_quantity = fields.Function(fields.Float('Purchase Quantity',
|
||||
digits=(16, Eval('unit_digits', 2)),
|
||||
states={
|
||||
'invisible': ~Eval('purchase_visible', False),
|
||||
},
|
||||
depends=['purchase_visible', 'unit_digits']),
|
||||
'get_purchase_fields')
|
||||
purchase_unit = fields.Function(fields.Many2One('product.uom',
|
||||
'Purchase Unit', states={
|
||||
'invisible': ~Eval('purchase_visible', False),
|
||||
}, depends=['purchase_visible']), 'get_purchase_fields')
|
||||
purchase_unit_digits = fields.Function(fields.Integer(
|
||||
'Purchase Unit Digits'), 'get_purchase_fields')
|
||||
purchase_unit_price = fields.Function(fields.Numeric('Purchase Unit Price',
|
||||
digits=(16, 4), states={
|
||||
'invisible': ~Eval('purchase_visible', False),
|
||||
}, depends=['purchase_visible']), 'get_purchase_fields')
|
||||
purchase_currency = fields.Function(fields.Many2One('currency.currency',
|
||||
'Purchase Currency', states={
|
||||
'invisible': ~Eval('purchase_visible', False),
|
||||
}, depends=['purchase_visible']), 'get_purchase_fields')
|
||||
purchase_visible = fields.Function(fields.Boolean('Purchase Visible',
|
||||
on_change_with=['from_location']), 'on_change_with_purchase_visible')
|
||||
supplier = fields.Function(fields.Many2One('party.party', 'Supplier'),
|
||||
'get_supplier', searcher='search_supplier')
|
||||
purchase_exception_state = fields.Function(fields.Selection([
|
||||
('', ''),
|
||||
('ignored', 'Ignored'),
|
||||
('recreated', 'Recreated'),
|
||||
], 'Exception State'), 'get_purchase_exception_state')
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
TableHandler = backend.get('TableHandler')
|
||||
cursor = Transaction().cursor
|
||||
sql_table = cls.__table__()
|
||||
|
||||
super(Move, cls).__register__(module_name)
|
||||
|
||||
table = TableHandler(cursor, cls, module_name)
|
||||
|
||||
# Migration from 2.6: remove purchase_line
|
||||
if table.column_exist('purchase_line'):
|
||||
cursor.execute(*sql_table.update(
|
||||
columns=[sql_table.origin],
|
||||
values=[Concat('purchase.line,', sql_table.purchase_line)],
|
||||
where=sql_table.purchase_line != None))
|
||||
table.drop_column('purchase_line')
|
||||
|
||||
@classmethod
|
||||
def _get_origin(cls):
|
||||
models = super(Move, cls)._get_origin()
|
||||
models.append('purchase.line')
|
||||
return models
|
||||
|
||||
def get_purchase(self, name):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
if isinstance(self.origin, PurchaseLine):
|
||||
return self.origin.purchase.id
|
||||
|
||||
@classmethod
|
||||
def search_purchase(cls, name, clause):
|
||||
return [('origin.' + name,) + tuple(clause[1:]) + ('purchase.line',)]
|
||||
|
||||
def get_purchase_exception_state(self, name):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
if not isinstance(self.origin, PurchaseLine):
|
||||
return ''
|
||||
if self in self.origin.moves_recreated:
|
||||
return 'recreated'
|
||||
if self in self.origin.moves_ignored:
|
||||
return 'ignored'
|
||||
|
||||
def get_purchase_fields(self, name):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
if isinstance(self.origin, PurchaseLine):
|
||||
if name[9:] == 'currency':
|
||||
return self.origin.purchase.currency.id
|
||||
elif name[9:] in ('quantity', 'unit_digits', 'unit_price'):
|
||||
return getattr(self.origin, name[9:])
|
||||
else:
|
||||
return getattr(self.origin, name[9:]).id
|
||||
else:
|
||||
if name[9:] == 'quantity':
|
||||
return 0.0
|
||||
elif name[9:] == 'unit_digits':
|
||||
return 2
|
||||
|
||||
def on_change_with_purchase_visible(self, name=None):
|
||||
if self.from_location:
|
||||
if self.from_location.type == 'supplier':
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_supplier(self, name):
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
if isinstance(self.origin, PurchaseLine):
|
||||
return self.origin.purchase.party.id
|
||||
|
||||
@property
|
||||
def origin_name(self):
|
||||
pool = Pool()
|
||||
PurchaseLine = pool.get('purchase.line')
|
||||
name = super(Move, self).origin_name
|
||||
if isinstance(self.origin, PurchaseLine):
|
||||
name = self.origin.purchase.rec_name
|
||||
return name
|
||||
|
||||
@classmethod
|
||||
def search_supplier(cls, name, clause):
|
||||
return [('origin.purchase.party',) + tuple(clause[1:]) +
|
||||
('purchase.line',)]
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('cancel')
|
||||
def cancel(cls, moves):
|
||||
pool = Pool()
|
||||
Purchase = pool.get('purchase.purchase')
|
||||
PurchaseLine = pool.get('purchase.line')
|
||||
|
||||
super(Move, cls).cancel(moves)
|
||||
purchase_lines = PurchaseLine.search([
|
||||
('moves', 'in', [m.id for m in moves]),
|
||||
])
|
||||
if purchase_lines:
|
||||
purchase_ids = list(set(l.purchase.id for l in purchase_lines))
|
||||
with Transaction().set_user(0, set_context=True):
|
||||
purchases = Purchase.browse(purchase_ids)
|
||||
Purchase.process(purchases)
|
||||
|
||||
@classmethod
|
||||
def delete(cls, moves):
|
||||
pool = Pool()
|
||||
Purchase = pool.get('purchase.purchase')
|
||||
PurchaseLine = pool.get('purchase.line')
|
||||
|
||||
purchases = set()
|
||||
purchase_lines = PurchaseLine.search([
|
||||
('moves', 'in', [m.id for m in moves]),
|
||||
])
|
||||
|
||||
super(Move, cls).delete(moves)
|
||||
|
||||
if purchase_lines:
|
||||
for purchase_line in purchase_lines:
|
||||
purchases.add(purchase_line.purchase)
|
||||
if purchases:
|
||||
with Transaction().set_user(0, set_context=True):
|
||||
purchases = Purchase.browse([p.id for p in purchases])
|
||||
Purchase.process(purchases)
|
||||
|
||||
|
||||
class OpenProductQuantitiesByWarehouse(Wizard):
|
||||
|
||||
Reference in New Issue
Block a user