[FIX] sale: bad indentation

[FIX] sale: pep8

bzr revid: olt@tinyerp.com-20090826134153-biu238mi160kijfd
This commit is contained in:
Olivier Laurent 2009-08-26 15:41:53 +02:00
parent 804178a2fe
commit fa29dc7d9e
1 changed files with 211 additions and 194 deletions

View File

@ -23,39 +23,42 @@
import time import time
import netsvc import netsvc
from osv import fields, osv from osv import fields, osv
import ir
from mx import DateTime from mx import DateTime
from tools import config from tools import config
from tools.translate import _ from tools.translate import _
class sale_shop(osv.osv): class sale_shop(osv.osv):
_name = "sale.shop" _name = "sale.shop"
_description = "Sale Shop" _description = "Sale Shop"
_columns = { _columns = {
'name': fields.char('Shop Name',size=64, required=True), 'name': fields.char('Shop Name', size=64, required=True),
'payment_default_id': fields.many2one('account.payment.term','Default Payment Term',required=True), 'payment_default_id': fields.many2one('account.payment.term', 'Default Payment Term', required=True),
'payment_account_id': fields.many2many('account.account','sale_shop_account','shop_id','account_id','Payment Accounts'), 'payment_account_id': fields.many2many('account.account', 'sale_shop_account', 'shop_id', 'account_id', 'Payment Accounts'),
'warehouse_id': fields.many2one('stock.warehouse','Warehouse'), 'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse'),
'pricelist_id': fields.many2one('product.pricelist', 'Pricelist'), 'pricelist_id': fields.many2one('product.pricelist', 'Pricelist'),
'project_id': fields.many2one('account.analytic.account', 'Analytic Account'), 'project_id': fields.many2one('account.analytic.account', 'Analytic Account'),
} }
sale_shop() sale_shop()
def _incoterm_get(self, cr, uid, context={}): def _incoterm_get(self, cr, uid, context={}):
cr.execute('select code, code||\', \'||name from stock_incoterms where active') cr.execute('select code, code||\', \'||name from stock_incoterms where active')
return cr.fetchall() return cr.fetchall()
class sale_order(osv.osv): class sale_order(osv.osv):
_name = "sale.order" _name = "sale.order"
_description = "Sale Order" _description = "Sale Order"
def copy(self, cr, uid, id, default=None,context={}):
def copy(self, cr, uid, id, default=None, context={}):
if not default: if not default:
default = {} default = {}
default.update({ default.update({
'state':'draft', 'state': 'draft',
'shipped':False, 'shipped': False,
'invoice_ids':[], 'invoice_ids': [],
'picking_ids':[], 'picking_ids': [],
'name': self.pool.get('ir.sequence').get(cr, uid, 'sale.order'), 'name': self.pool.get('ir.sequence').get(cr, uid, 'sale.order'),
}) })
return super(sale_order, self).copy(cr, uid, id, default, context) return super(sale_order, self).copy(cr, uid, id, default, context)
@ -63,12 +66,12 @@ class sale_order(osv.osv):
def _amount_line_tax(self, cr, uid, line, context={}): def _amount_line_tax(self, cr, uid, line, context={}):
val = 0.0 val = 0.0
for c in self.pool.get('account.tax').compute(cr, uid, line.tax_id, line.price_unit * (1-(line.discount or 0.0)/100.0), line.product_uom_qty, line.order_id.partner_invoice_id.id, line.product_id, line.order_id.partner_id): for c in self.pool.get('account.tax').compute(cr, uid, line.tax_id, line.price_unit * (1-(line.discount or 0.0)/100.0), line.product_uom_qty, line.order_id.partner_invoice_id.id, line.product_id, line.order_id.partner_id):
val+= c['amount'] val += c['amount']
return val return val
def _amount_all(self, cr, uid, ids, field_name, arg, context): def _amount_all(self, cr, uid, ids, field_name, arg, context):
res = {} res = {}
cur_obj=self.pool.get('res.currency') cur_obj = self.pool.get('res.currency')
for order in self.browse(cr, uid, ids): for order in self.browse(cr, uid, ids):
res[order.id] = { res[order.id] = {
'amount_untaxed': 0.0, 'amount_untaxed': 0.0,
@ -76,20 +79,21 @@ class sale_order(osv.osv):
'amount_total': 0.0, 'amount_total': 0.0,
} }
val = val1 = 0.0 val = val1 = 0.0
cur=order.pricelist_id.currency_id cur = order.pricelist_id.currency_id
for line in order.order_line: for line in order.order_line:
val1 += line.price_subtotal val1 += line.price_subtotal
val += self._amount_line_tax(cr, uid, line, context) val += self._amount_line_tax(cr, uid, line, context)
res[order.id]['amount_tax']=cur_obj.round(cr, uid, cur, val) res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val)
res[order.id]['amount_untaxed']=cur_obj.round(cr, uid, cur, val1) res[order.id]['amount_untaxed'] = cur_obj.round(cr, uid, cur, val1)
res[order.id]['amount_total']=res[order.id]['amount_untaxed'] + res[order.id]['amount_tax'] res[order.id]['amount_total'] = res[order.id]['amount_untaxed'] + res[order.id]['amount_tax']
return res return res
def _picked_rate(self, cr, uid, ids, name, arg, context=None): def _picked_rate(self, cr, uid, ids, name, arg, context=None):
if not ids: return {} if not ids:
return {}
res = {} res = {}
for id in ids: for id in ids:
res[id] = [0.0,0.0] res[id] = [0.0, 0.0]
cr.execute('''SELECT cr.execute('''SELECT
p.sale_id,sum(m.product_qty), m.state p.sale_id,sum(m.product_qty), m.state
FROM FROM
@ -97,12 +101,12 @@ class sale_order(osv.osv):
LEFT JOIN LEFT JOIN
stock_picking p on (p.id=m.picking_id) stock_picking p on (p.id=m.picking_id)
WHERE WHERE
p.sale_id in ('''+','.join(map(str,ids))+''') p.sale_id in ('''+','.join(map(str, ids))+''')
GROUP BY m.state, p.sale_id''') GROUP BY m.state, p.sale_id''')
for oid,nbr,state in cr.fetchall(): for oid, nbr, state in cr.fetchall():
if state=='cancel': if state == 'cancel':
continue continue
if state=='done': if state == 'done':
res[oid][0] += nbr or 0.0 res[oid][0] += nbr or 0.0
res[oid][1] += nbr or 0.0 res[oid][1] += nbr or 0.0
else: else:
@ -125,7 +129,7 @@ class sale_order(osv.osv):
continue continue
tot = 0.0 tot = 0.0
for invoice in sale.invoice_ids: for invoice in sale.invoice_ids:
if invoice.state not in ('draft','cancel'): if invoice.state not in ('draft', 'cancel'):
tot += invoice.amount_untaxed tot += invoice.amount_untaxed
if tot: if tot:
@ -139,7 +143,7 @@ class sale_order(osv.osv):
for sale in self.browse(cursor, user, ids, context=context): for sale in self.browse(cursor, user, ids, context=context):
res[sale.id] = True res[sale.id] = True
for invoice in sale.invoice_ids: for invoice in sale.invoice_ids:
if invoice.state <> 'paid': if invoice.state != 'paid':
res[sale.id] = False res[sale.id] = False
break break
if not sale.invoice_ids: if not sale.invoice_ids:
@ -181,49 +185,49 @@ class sale_order(osv.osv):
_columns = { _columns = {
'name': fields.char('Order Reference', size=64, required=True, select=True), 'name': fields.char('Order Reference', size=64, required=True, select=True),
'shop_id':fields.many2one('sale.shop', 'Shop', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'shop_id': fields.many2one('sale.shop', 'Shop', required=True, readonly=True, states={'draft': [('readonly', False)]}),
'origin': fields.char('Origin', size=64), 'origin': fields.char('Origin', size=64),
'client_order_ref': fields.char('Customer Ref',size=64), 'client_order_ref': fields.char('Customer Ref', size=64),
'state': fields.selection([ 'state': fields.selection([
('draft','Quotation'), ('draft', 'Quotation'),
('waiting_date','Waiting Schedule'), ('waiting_date', 'Waiting Schedule'),
('manual','Manual In Progress'), ('manual', 'Manual In Progress'),
('progress','In Progress'), ('progress', 'In Progress'),
('shipping_except','Shipping Exception'), ('shipping_except', 'Shipping Exception'),
('invoice_except','Invoice Exception'), ('invoice_except', 'Invoice Exception'),
('done','Done'), ('done', 'Done'),
('cancel','Cancelled') ('cancel', 'Cancelled')
], 'Order State', readonly=True, help="Gives the state of the quotation or sale order. The exception state is automatically set when a cancel operation occurs in the invoice validation (Invoice Exception) or in the packing list process (Shipping Exception). The 'Waiting Schedule' state is set when the invoice is confirmed but waiting for the scheduler to run on the date 'Date Ordered'.", select=True), ], 'Order State', readonly=True, help="Gives the state of the quotation or sale order. The exception state is automatically set when a cancel operation occurs in the invoice validation (Invoice Exception) or in the packing list process (Shipping Exception). The 'Waiting Schedule' state is set when the invoice is confirmed but waiting for the scheduler to run on the date 'Date Ordered'.", select=True),
'date_order':fields.date('Date Ordered', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'date_order': fields.date('Date Ordered', required=True, readonly=True, states={'draft': [('readonly', False)]}),
'user_id':fields.many2one('res.users', 'Salesman', states={'draft':[('readonly',False)]}, select=True), 'user_id': fields.many2one('res.users', 'Salesman', states={'draft': [('readonly', False)]}, select=True),
'partner_id':fields.many2one('res.partner', 'Customer', readonly=True, states={'draft':[('readonly',False)]}, required=True, change_default=True, select=True), 'partner_id': fields.many2one('res.partner', 'Customer', readonly=True, states={'draft': [('readonly', False)]}, required=True, change_default=True, select=True),
'partner_invoice_id':fields.many2one('res.partner.address', 'Invoice Address', readonly=True, required=True, states={'draft':[('readonly',False)]}), 'partner_invoice_id': fields.many2one('res.partner.address', 'Invoice Address', readonly=True, required=True, states={'draft': [('readonly', False)]}),
'partner_order_id':fields.many2one('res.partner.address', 'Ordering Contact', readonly=True, required=True, states={'draft':[('readonly',False)]}, help="The name and address of the contact that requested the order or quotation."), 'partner_order_id': fields.many2one('res.partner.address', 'Ordering Contact', readonly=True, required=True, states={'draft': [('readonly', False)]}, help="The name and address of the contact that requested the order or quotation."),
'partner_shipping_id':fields.many2one('res.partner.address', 'Shipping Address', readonly=True, required=True, states={'draft':[('readonly',False)]}), 'partner_shipping_id': fields.many2one('res.partner.address', 'Shipping Address', readonly=True, required=True, states={'draft': [('readonly', False)]}),
'incoterm': fields.selection(_incoterm_get, 'Incoterm',size=3), 'incoterm': fields.selection(_incoterm_get, 'Incoterm', size=3),
'picking_policy': fields.selection([('direct','Partial Delivery'),('one','Complete Delivery')], 'picking_policy': fields.selection([('direct', 'Partial Delivery'), ('one', 'Complete Delivery')],
'Packing Policy', required=True, help="""If you don't have enough stock available to deliver all at once, do you accept partial shipments or not?"""), 'Packing Policy', required=True, help="""If you don't have enough stock available to deliver all at once, do you accept partial shipments or not?"""),
'order_policy': fields.selection([ 'order_policy': fields.selection([
('prepaid','Payment Before Delivery'), ('prepaid', 'Payment Before Delivery'),
('manual','Shipping & Manual Invoice'), ('manual', 'Shipping & Manual Invoice'),
('postpaid','Invoice on Order After Delivery'), ('postpaid', 'Invoice on Order After Delivery'),
('picking','Invoice from the Packing'), ('picking', 'Invoice from the Packing'),
], 'Shipping Policy', required=True, readonly=True, states={'draft':[('readonly',False)]}, ], 'Shipping Policy', required=True, readonly=True, states={'draft': [('readonly', False)]},
help="""The Shipping Policy is used to synchronise invoice and delivery operations. help="""The Shipping Policy is used to synchronise invoice and delivery operations.
- The 'Pay before delivery' choice will first generate the invoice and then generate the packing order after the payment of this invoice. - The 'Pay before delivery' choice will first generate the invoice and then generate the packing order after the payment of this invoice.
- The 'Shipping & Manual Invoice' will create the packing order directly and wait for the user to manually click on the 'Invoice' button to generate the draft invoice. - The 'Shipping & Manual Invoice' will create the packing order directly and wait for the user to manually click on the 'Invoice' button to generate the draft invoice.
- The 'Invoice on Order After Delivery' choice will generate the draft invoice based on sale order after all packing lists have been finished. - The 'Invoice on Order After Delivery' choice will generate the draft invoice based on sale order after all packing lists have been finished.
- The 'Invoice from the packing' choice is used to create an invoice during the packing process."""), - The 'Invoice from the packing' choice is used to create an invoice during the packing process."""),
'pricelist_id':fields.many2one('product.pricelist', 'Pricelist', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', required=True, readonly=True, states={'draft': [('readonly', False)]}),
'project_id':fields.many2one('account.analytic.account', 'Analytic Account', readonly=True, states={'draft':[('readonly', False)]}), 'project_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True, states={'draft': [('readonly', False)]}),
'order_line': fields.one2many('sale.order.line', 'order_id', 'Order Lines', readonly=True, states={'draft':[('readonly',False)]}), 'order_line': fields.one2many('sale.order.line', 'order_id', 'Order Lines', readonly=True, states={'draft': [('readonly', False)]}),
'invoice_ids': fields.many2many('account.invoice', 'sale_order_invoice_rel', 'order_id', 'invoice_id', 'Invoice', help="This is the list of invoices that have been generated for this sale order. The same sale order may have been invoiced in several times (by line for example)."), 'invoice_ids': fields.many2many('account.invoice', 'sale_order_invoice_rel', 'order_id', 'invoice_id', 'Invoice', help="This is the list of invoices that have been generated for this sale order. The same sale order may have been invoiced in several times (by line for example)."),
'picking_ids': fields.one2many('stock.picking', 'sale_id', 'Related Packing', readonly=True, help="This is the list of picking list that have been generated for this invoice"), 'picking_ids': fields.one2many('stock.picking', 'sale_id', 'Related Packing', readonly=True, help="This is the list of picking list that have been generated for this invoice"),
'shipped':fields.boolean('Picked', readonly=True), 'shipped': fields.boolean('Picked', readonly=True),
'picked_rate': fields.function(_picked_rate, method=True, string='Picked', type='float'), 'picked_rate': fields.function(_picked_rate, method=True, string='Picked', type='float'),
'invoiced_rate': fields.function(_invoiced_rate, method=True, string='Invoiced', type='float'), 'invoiced_rate': fields.function(_invoiced_rate, method=True, string='Invoiced', type='float'),
'invoiced': fields.function(_invoiced, method=True, string='Paid', 'invoiced': fields.function(_invoiced, method=True, string='Paid',
@ -231,26 +235,26 @@ class sale_order(osv.osv):
'note': fields.text('Notes'), 'note': fields.text('Notes'),
'amount_untaxed': fields.function(_amount_all, method=True, string='Untaxed Amount', 'amount_untaxed': fields.function(_amount_all, method=True, string='Untaxed Amount',
store={ store = {
'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10), 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
'sale.order.line': (_get_order, ['price_unit','tax_id','discount','product_uom_qty'], 10), 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
}, },
multi='sums'), multi='sums'),
'amount_tax': fields.function(_amount_all, method=True, string='Taxes', 'amount_tax': fields.function(_amount_all, method=True, string='Taxes',
store={ store = {
'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10), 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
'sale.order.line': (_get_order, ['price_unit','tax_id','discount','product_uom_qty'], 10), 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
}, },
multi='sums'), multi='sums'),
'amount_total': fields.function(_amount_all, method=True, string='Total', 'amount_total': fields.function(_amount_all, method=True, string='Total',
store={ store = {
'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10), 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
'sale.order.line': (_get_order, ['price_unit','tax_id','discount','product_uom_qty'], 10), 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
}, },
multi='sums'), multi='sums'),
'invoice_quantity': fields.selection([('order','Ordered Quantities'),('procurement','Shipped Quantities')], 'Invoice on', help="The sale order will automatically create the invoice proposition (draft invoice). Ordered and delivered quantities may not be the same. You have to choose if you invoice based on ordered or shipped quantities. If the product is a service, shipped quantities means hours spent on the associated tasks.",required=True), 'invoice_quantity': fields.selection([('order', 'Ordered Quantities'), ('procurement', 'Shipped Quantities')], 'Invoice on', help="The sale order will automatically create the invoice proposition (draft invoice). Ordered and delivered quantities may not be the same. You have to choose if you invoice based on ordered or shipped quantities. If the product is a service, shipped quantities means hours spent on the associated tasks.", required=True),
'payment_term' : fields.many2one('account.payment.term', 'Payment Term'), 'payment_term': fields.many2one('account.payment.term', 'Payment Term'),
'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position') 'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position')
} }
_defaults = { _defaults = {
@ -273,31 +277,30 @@ class sale_order(osv.osv):
sale_orders = self.read(cr, uid, ids, ['state']) sale_orders = self.read(cr, uid, ids, ['state'])
unlink_ids = [] unlink_ids = []
for s in sale_orders: for s in sale_orders:
if s['state'] in ['draft','cancel']: if s['state'] in ['draft', 'cancel']:
unlink_ids.append(s['id']) unlink_ids.append(s['id'])
else: else:
raise osv.except_osv(_('Invalid action !'), _('Cannot delete Sale Order(s) which are already confirmed !')) raise osv.except_osv(_('Invalid action !'), _('Cannot delete Sale Order(s) which are already confirmed !'))
return osv.osv.unlink(self, cr, uid, unlink_ids, context=context) return osv.osv.unlink(self, cr, uid, unlink_ids, context=context)
def onchange_shop_id(self, cr, uid, ids, shop_id): def onchange_shop_id(self, cr, uid, ids, shop_id):
v={} v = {}
if shop_id: if shop_id:
shop=self.pool.get('sale.shop').browse(cr,uid,shop_id) shop = self.pool.get('sale.shop').browse(cr, uid, shop_id)
v['project_id']=shop.project_id.id v['project_id'] = shop.project_id.id
# Que faire si le client a une pricelist a lui ? # Que faire si le client a une pricelist a lui ?
if shop.pricelist_id.id: if shop.pricelist_id.id:
v['pricelist_id']=shop.pricelist_id.id v['pricelist_id'] = shop.pricelist_id.id
#v['payment_default_id']=shop.payment_default_id.id #v['payment_default_id']=shop.payment_default_id.id
return {'value':v} return {'value': v}
def action_cancel_draft(self, cr, uid, ids, *args): def action_cancel_draft(self, cr, uid, ids, *args):
if not len(ids): if not len(ids):
return False return False
cr.execute('select id from sale_order_line where order_id in ('+','.join(map(str, ids))+')', ('draft',)) cr.execute('select id from sale_order_line where order_id in ('+','.join(map(str, ids))+')', ('draft',))
line_ids = map(lambda x: x[0], cr.fetchall()) line_ids = map(lambda x: x[0], cr.fetchall())
self.write(cr, uid, ids, {'state':'draft', 'invoice_ids':[], 'shipped':0}) self.write(cr, uid, ids, {'state': 'draft', 'invoice_ids': [], 'shipped': 0})
self.pool.get('sale.order.line').write(cr, uid, line_ids, {'invoiced':False, 'state':'draft', 'invoice_lines':[(6,0,[])]}) self.pool.get('sale.order.line').write(cr, uid, line_ids, {'invoiced': False, 'state': 'draft', 'invoice_lines': [(6, 0, [])]})
wf_service = netsvc.LocalService("workflow") wf_service = netsvc.LocalService("workflow")
for inv_id in ids: for inv_id in ids:
wf_service.trg_create(uid, 'sale.order', inv_id, cr) wf_service.trg_create(uid, 'sale.order', inv_id, cr)
@ -305,41 +308,41 @@ class sale_order(osv.osv):
def onchange_partner_id(self, cr, uid, ids, part): def onchange_partner_id(self, cr, uid, ids, part):
if not part: if not part:
return {'value':{'partner_invoice_id': False, 'partner_shipping_id':False, 'partner_order_id':False, 'payment_term' : False, 'fiscal_position': False}} return {'value': {'partner_invoice_id': False, 'partner_shipping_id': False, 'partner_order_id': False, 'payment_term': False, 'fiscal_position': False}}
addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['delivery','invoice','contact']) addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['delivery', 'invoice', 'contact'])
part = self.pool.get('res.partner').browse(cr, uid, part) part = self.pool.get('res.partner').browse(cr, uid, part)
pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False
payment_term = part.property_payment_term and part.property_payment_term.id or False payment_term = part.property_payment_term and part.property_payment_term.id or False
fiscal_position = part.property_account_position and part.property_account_position.id or False fiscal_position = part.property_account_position and part.property_account_position.id or False
val = {'partner_invoice_id': addr['invoice'], 'partner_order_id':addr['contact'], 'partner_shipping_id':addr['delivery'], 'payment_term' : payment_term, 'fiscal_position': fiscal_position} val = {'partner_invoice_id': addr['invoice'], 'partner_order_id': addr['contact'], 'partner_shipping_id': addr['delivery'], 'payment_term': payment_term, 'fiscal_position': fiscal_position}
if pricelist: if pricelist:
val['pricelist_id'] = pricelist val['pricelist_id'] = pricelist
return {'value':val} return {'value': val}
def shipping_policy_change(self, cr, uid, ids, policy, context={}): def shipping_policy_change(self, cr, uid, ids, policy, context={}):
if not policy: if not policy:
return {} return {}
inv_qty = 'order' inv_qty = 'order'
if policy=='prepaid': if policy == 'prepaid':
inv_qty = 'order' inv_qty = 'order'
elif policy=='picking': elif policy == 'picking':
inv_qty = 'procurement' inv_qty = 'procurement'
return {'value':{'invoice_quantity':inv_qty}} return {'value': {'invoice_quantity': inv_qty}}
def write(self, cr, uid, ids, vals, context=None): def write(self, cr, uid, ids, vals, context=None):
if vals.has_key('order_policy'): if 'order_policy' in vals:
if vals['order_policy']=='prepaid': if vals['order_policy'] == 'prepaid':
vals.update({'invoice_quantity':'order'}) vals.update({'invoice_quantity': 'order'})
elif vals['order_policy']=='picking': elif vals['order_policy'] == 'picking':
vals.update({'invoice_quantity':'procurement'}) vals.update({'invoice_quantity': 'procurement'})
return super(sale_order, self).write(cr, uid, ids, vals, context=context) return super(sale_order, self).write(cr, uid, ids, vals, context=context)
def create(self, cr, uid, vals, context={}): def create(self, cr, uid, vals, context={}):
if vals.has_key('order_policy'): if 'order_policy' in vals:
if vals['order_policy']=='prepaid': if vals['order_policy'] == 'prepaid':
vals.update({'invoice_quantity':'order'}) vals.update({'invoice_quantity': 'order'})
if vals['order_policy']=='picking': if vals['order_policy'] == 'picking':
vals.update({'invoice_quantity':'procurement'}) vals.update({'invoice_quantity': 'procurement'})
return super(sale_order, self).create(cr, uid, vals, context=context) return super(sale_order, self).create(cr, uid, vals, context=context)
def button_dummy(self, cr, uid, ids, context={}): def button_dummy(self, cr, uid, ids, context={}):
@ -352,7 +355,7 @@ class sale_order(osv.osv):
def _inv_get(self, cr, uid, order, context={}): def _inv_get(self, cr, uid, order, context={}):
return {} return {}
def _make_invoice(self, cr, uid, order, lines,context={}): def _make_invoice(self, cr, uid, order, lines, context={}):
a = order.partner_id.property_account_receivable.id a = order.partner_id.property_account_receivable.id
if order.payment_term: if order.payment_term:
pay_term = order.payment_term.id pay_term = order.payment_term.id
@ -361,19 +364,19 @@ class sale_order(osv.osv):
for preinv in order.invoice_ids: for preinv in order.invoice_ids:
if preinv.state not in ('cancel',): if preinv.state not in ('cancel',):
for preline in preinv.invoice_line: for preline in preinv.invoice_line:
inv_line_id = self.pool.get('account.invoice.line').copy(cr, uid, preline.id, {'invoice_id':False, 'price_unit':-preline.price_unit}) inv_line_id = self.pool.get('account.invoice.line').copy(cr, uid, preline.id, {'invoice_id': False, 'price_unit': -preline.price_unit})
lines.append(inv_line_id) lines.append(inv_line_id)
inv = { inv = {
'name': order.client_order_ref or order.name, 'name': order.client_order_ref or order.name,
'origin': order.name, 'origin': order.name,
'type': 'out_invoice', 'type': 'out_invoice',
'reference': "P%dSO%d"%(order.partner_id.id,order.id), 'reference': "P%dSO%d" % (order.partner_id.id, order.id),
'account_id': a, 'account_id': a,
'partner_id': order.partner_id.id, 'partner_id': order.partner_id.id,
'address_invoice_id': order.partner_invoice_id.id, 'address_invoice_id': order.partner_invoice_id.id,
'address_contact_id': order.partner_invoice_id.id, 'address_contact_id': order.partner_invoice_id.id,
'invoice_line': [(6,0,lines)], 'invoice_line': [(6, 0, lines)],
'currency_id' : order.pricelist_id.currency_id.id, 'currency_id': order.pricelist_id.currency_id.id,
'comment': order.note, 'comment': order.note,
'payment_term': pay_term, 'payment_term': pay_term,
'fiscal_position': order.partner_id.property_account_position.id 'fiscal_position': order.partner_id.property_account_position.id
@ -381,20 +384,18 @@ class sale_order(osv.osv):
inv_obj = self.pool.get('account.invoice') inv_obj = self.pool.get('account.invoice')
inv.update(self._inv_get(cr, uid, order)) inv.update(self._inv_get(cr, uid, order))
inv_id = inv_obj.create(cr, uid, inv) inv_id = inv_obj.create(cr, uid, inv)
data = inv_obj.onchange_payment_term_date_invoice(cr, uid, [inv_id], data = inv_obj.onchange_payment_term_date_invoice(cr, uid, [inv_id], pay_term, time.strftime('%Y-%m-%d'))
pay_term,time.strftime('%Y-%m-%d')) if data.get('value', False):
if data.get('value',False):
inv_obj.write(cr, uid, [inv_id], data['value'], context=context) inv_obj.write(cr, uid, [inv_id], data['value'], context=context)
inv_obj.button_compute(cr, uid, [inv_id]) inv_obj.button_compute(cr, uid, [inv_id])
return inv_id return inv_id
def action_invoice_create(self, cr, uid, ids, grouped=False, states=['confirmed', 'done', 'exception']):
def action_invoice_create(self, cr, uid, ids, grouped=False, states=['confirmed','done','exception']):
res = False res = False
invoices = {} invoices = {}
invoice_ids = [] invoice_ids = []
for o in self.browse(cr,uid,ids): for o in self.browse(cr, uid, ids):
lines = [] lines = []
for line in o.order_line: for line in o.order_line:
if (line.state in states) and not line.invoiced: if (line.state in states) and not line.invoiced:
@ -408,64 +409,63 @@ class sale_order(osv.osv):
for i in o.invoice_ids: for i in o.invoice_ids:
if i.state == 'draft': if i.state == 'draft':
return i.id return i.id
picking_obj=self.pool.get('stock.picking') picking_obj = self.pool.get('stock.picking')
for val in invoices.values(): for val in invoices.values():
if grouped: if grouped:
res = self._make_invoice(cr, uid, val[0][0], reduce(lambda x,y: x + y, [l for o,l in val], [])) res = self._make_invoice(cr, uid, val[0][0], reduce(lambda x, y: x + y, [l for o, l in val], []))
for o,l in val: for o, l in val:
self.write(cr, uid, [o.id], {'state' : 'progress'}) self.write(cr, uid, [o.id], {'state': 'progress'})
if o.order_policy=='picking': if o.order_policy == 'picking':
picking_obj.write(cr,uid,map(lambda x:x.id,o.picking_ids),{'invoice_state':'invoiced'}) picking_obj.write(cr, uid, map(lambda x: x.id, o.picking_ids), {'invoice_state': 'invoiced'})
cr.execute('insert into sale_order_invoice_rel (order_id,invoice_id) values (%s,%s)', (o.id, res)) cr.execute('insert into sale_order_invoice_rel (order_id,invoice_id) values (%s,%s)', (o.id, res))
else: else:
for order, il in val: for order, il in val:
res = self._make_invoice(cr, uid, order, il) res = self._make_invoice(cr, uid, order, il)
invoice_ids.append(res) invoice_ids.append(res)
self.write(cr, uid, [order.id], {'state' : 'progress'}) self.write(cr, uid, [order.id], {'state': 'progress'})
if order.order_policy=='picking': if order.order_policy == 'picking':
picking_obj.write(cr,uid,map(lambda x:x.id,order.picking_ids),{'invoice_state':'invoiced'}) picking_obj.write(cr, uid, map(lambda x: x.id, order.picking_ids), {'invoice_state': 'invoiced'})
cr.execute('insert into sale_order_invoice_rel (order_id,invoice_id) values (%s,%s)', (order.id, res)) cr.execute('insert into sale_order_invoice_rel (order_id,invoice_id) values (%s,%s)', (order.id, res))
return res return res
def action_invoice_cancel(self, cr, uid, ids, context={}): def action_invoice_cancel(self, cr, uid, ids, context={}):
for sale in self.browse(cr, uid, ids): for sale in self.browse(cr, uid, ids):
for line in sale.order_line: for line in sale.order_line:
invoiced=False invoiced = False
for iline in line.invoice_lines: for iline in line.invoice_lines:
if iline.invoice_id and iline.invoice_id.state == 'cancel': if iline.invoice_id and iline.invoice_id.state == 'cancel':
continue continue
else: else:
invoiced=True invoiced = True
self.pool.get('sale.order.line').write(cr, uid, [line.id], {'invoiced': invoiced}) self.pool.get('sale.order.line').write(cr, uid, [line.id], {'invoiced': invoiced})
self.write(cr, uid, ids, {'state':'invoice_except', 'invoice_ids':False}) self.write(cr, uid, ids, {'state': 'invoice_except', 'invoice_ids': False})
return True return True
def action_cancel(self, cr, uid, ids, context={}): def action_cancel(self, cr, uid, ids, context={}):
ok = True ok = True
sale_order_line_obj = self.pool.get('sale.order.line') sale_order_line_obj = self.pool.get('sale.order.line')
for sale in self.browse(cr, uid, ids): for sale in self.browse(cr, uid, ids):
for pick in sale.picking_ids: for pick in sale.picking_ids:
if pick.state not in ('draft','cancel'): if pick.state not in ('draft', 'cancel'):
raise osv.except_osv( raise osv.except_osv(
_('Could not cancel sale order !'), _('Could not cancel sale order !'),
_('You must first cancel all packing attached to this sale order.')) _('You must first cancel all packing attached to this sale order.'))
for r in self.read(cr,uid,ids,['picking_ids']): for r in self.read(cr, uid, ids, ['picking_ids']):
for pick in r['picking_ids']: for pick in r['picking_ids']:
wf_service = netsvc.LocalService("workflow") wf_service = netsvc.LocalService("workflow")
wf_service.trg_validate(uid, 'stock.picking', pick, 'button_cancel', cr) wf_service.trg_validate(uid, 'stock.picking', pick, 'button_cancel', cr)
for inv in sale.invoice_ids: for inv in sale.invoice_ids:
if inv.state not in ('draft','cancel'): if inv.state not in ('draft', 'cancel'):
raise osv.except_osv( raise osv.except_osv(
_('Could not cancel this sale order !'), _('Could not cancel this sale order !'),
_('You must first cancel all invoices attached to this sale order.')) _('You must first cancel all invoices attached to this sale order.'))
for r in self.read(cr,uid,ids,['invoice_ids']): for r in self.read(cr, uid, ids, ['invoice_ids']):
for inv in r['invoice_ids']: for inv in r['invoice_ids']:
wf_service = netsvc.LocalService("workflow") wf_service = netsvc.LocalService("workflow")
wf_service.trg_validate(uid, 'account.invoice', inv, 'invoice_cancel', cr) wf_service.trg_validate(uid, 'account.invoice', inv, 'invoice_cancel', cr)
sale_order_line_obj.write(cr, uid, [l.id for l in sale.order_line], sale_order_line_obj.write(cr, uid, [l.id for l in sale.order_line],
{'state': 'cancel'}) {'state': 'cancel'})
self.write(cr,uid,ids,{'state':'cancel'}) self.write(cr, uid, ids, {'state': 'cancel'})
return True return True
def action_wait(self, cr, uid, ids, *args): def action_wait(self, cr, uid, ids, *args):
@ -525,22 +525,22 @@ class sale_order(osv.osv):
if write_cancel_ids: if write_cancel_ids:
self.pool.get('sale.order.line').write(cr, uid, write_cancel_ids, {'state': 'exception'}) self.pool.get('sale.order.line').write(cr, uid, write_cancel_ids, {'state': 'exception'})
if mode=='finished': if mode == 'finished':
return finished return finished
elif mode=='canceled': elif mode == 'canceled':
return canceled return canceled
if notcanceled: if notcanceled:
return False return False
return canceled return canceled
def action_ship_create(self, cr, uid, ids, *args): def action_ship_create(self, cr, uid, ids, *args):
picking_id=False picking_id = False
company = self.pool.get('res.users').browse(cr, uid, uid).company_id company = self.pool.get('res.users').browse(cr, uid, uid).company_id
for order in self.browse(cr, uid, ids, context={}): for order in self.browse(cr, uid, ids, context={}):
output_id = order.shop_id.warehouse_id.lot_output_id.id output_id = order.shop_id.warehouse_id.lot_output_id.id
picking_id = False picking_id = False
for line in order.order_line: for line in order.order_line:
proc_id=False proc_id = False
date_planned = DateTime.now() + DateTime.RelativeDateTime(days=line.delay or 0.0) date_planned = DateTime.now() + DateTime.RelativeDateTime(days=line.delay or 0.0)
date_planned = (date_planned - DateTime.RelativeDateTime(days=company.security_lead)).strftime('%Y-%m-%d %H:%M:%S') date_planned = (date_planned - DateTime.RelativeDateTime(days=company.security_lead)).strftime('%Y-%m-%d %H:%M:%S')
if line.state == 'done': if line.state == 'done':
@ -571,8 +571,8 @@ class sale_order(osv.osv):
'product_uos_qty': line.product_uos_qty, 'product_uos_qty': line.product_uos_qty,
'product_uos': (line.product_uos and line.product_uos.id)\ 'product_uos': (line.product_uos and line.product_uos.id)\
or line.product_uom.id, or line.product_uom.id,
'product_packaging' : line.product_packaging.id, 'product_packaging': line.product_packaging.id,
'address_id' : line.address_allotment_id.id or order.partner_shipping_id.id, 'address_id': line.address_allotment_id.id or order.partner_shipping_id.id,
'location_id': location_id, 'location_id': location_id,
'location_dest_id': output_id, 'location_dest_id': output_id,
'sale_line_id': line.id, 'sale_line_id': line.id,
@ -600,7 +600,7 @@ class sale_order(osv.osv):
wf_service = netsvc.LocalService("workflow") wf_service = netsvc.LocalService("workflow")
wf_service.trg_validate(uid, 'mrp.procurement', proc_id, 'button_confirm', cr) wf_service.trg_validate(uid, 'mrp.procurement', proc_id, 'button_confirm', cr)
self.pool.get('sale.order.line').write(cr, uid, [line.id], {'procurement_id': proc_id}) self.pool.get('sale.order.line').write(cr, uid, [line.id], {'procurement_id': proc_id})
elif line.product_id and line.product_id.product_tmpl_id.type=='service': elif line.product_id and line.product_id.product_tmpl_id.type == 'service':
proc_id = self.pool.get('mrp.procurement').create(cr, uid, { proc_id = self.pool.get('mrp.procurement').create(cr, uid, {
'name': line.name, 'name': line.name,
'origin': order.name, 'origin': order.name,
@ -626,12 +626,12 @@ class sale_order(osv.osv):
wf_service = netsvc.LocalService("workflow") wf_service = netsvc.LocalService("workflow")
wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr) wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr)
if order.state=='shipping_except': if order.state == 'shipping_except':
val['state'] = 'progress' val['state'] = 'progress'
if (order.order_policy == 'manual'): if (order.order_policy == 'manual'):
for line in order.order_line: for line in order.order_line:
if (not line.invoiced) and (line.state not in ('cancel','draft')): if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
val['state'] = 'manual' val['state'] = 'manual'
break break
self.write(cr, uid, [order.id], val) self.write(cr, uid, [order.id], val)
@ -640,33 +640,48 @@ class sale_order(osv.osv):
def action_ship_end(self, cr, uid, ids, context={}): def action_ship_end(self, cr, uid, ids, context={}):
for order in self.browse(cr, uid, ids): for order in self.browse(cr, uid, ids):
val = {'shipped':True} val = {'shipped': True}
if order.state=='shipping_except': if order.state == 'shipping_except':
val['state'] = 'progress' val['state'] = 'progress'
if (order.order_policy == 'manual'): if (order.order_policy == 'manual'):
for line in order.order_line: for line in order.order_line:
if (not line.invoiced) and (line.state not in ('cancel','draft')): if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
val['state'] = 'manual' val['state'] = 'manual'
break break
for line in order.order_line: for line in order.order_line:
towrite = [] towrite = []
if line.state=='exception': if line.state == 'exception':
towrite.append(line.id) towrite.append(line.id)
if towrite: if towrite:
self.pool.get('sale.order.line').write(cr, uid, towrite, {'state':'done'},context=context) self.pool.get('sale.order.line').write(cr, uid, towrite, {'state': 'done'}, context=context)
self.write(cr, uid, [order.id], val) self.write(cr, uid, [order.id], val)
return True return True
def _log_event(self, cr, uid, ids, factor=0.7, name='Open Order'): def _log_event(self, cr, uid, ids, factor=0.7, name='Open Order'):
invs = self.read(cr, uid, ids, ['date_order','partner_id','amount_untaxed']) invs = self.read(cr, uid, ids, ['date_order', 'partner_id', 'amount_untaxed'])
for inv in invs: for inv in invs:
part=inv['partner_id'] and inv['partner_id'][0] part = inv['partner_id'] and inv['partner_id'][0]
pr = inv['amount_untaxed'] or 0.0 pr = inv['amount_untaxed'] or 0.0
partnertype = 'customer' partnertype = 'customer'
eventtype = 'sale' eventtype = 'sale'
self.pool.get('res.partner.event').create(cr, uid, {'name':'Order: '+name, 'som':False, 'description':'Order '+str(inv['id']), 'document':'', 'partner_id':part, 'date':time.strftime('%Y-%m-%d'), 'canal_id':False, 'user_id':uid, 'partner_type':partnertype, 'probability':1.0, 'planned_revenue':pr, 'planned_cost':0.0, 'type':eventtype}) event = {
'name': 'Order: '+name,
'som': False,
'description': 'Order '+str(inv['id']),
'document': '',
'partner_id': part,
'date': time.strftime('%Y-%m-%d'),
'canal_id': False,
'user_id': uid,
'partner_type': partnertype,
'probability': 1.0,
'planned_revenue': pr,
'planned_cost': 0.0,
'type': eventtype
}
self.pool.get('res.partner.event').create(cr, uid, event)
def has_stockable_products(self,cr, uid, ids, *args): def has_stockable_products(self, cr, uid, ids, *args):
for order in self.browse(cr, uid, ids): for order in self.browse(cr, uid, ids):
for order_line in order.order_line: for order_line in order.order_line:
if order_line.product_id and order_line.product_id.product_tmpl_id.type in ('product', 'consu'): if order_line.product_id and order_line.product_id.product_tmpl_id.type in ('product', 'consu'):
@ -686,7 +701,7 @@ class sale_order_line(osv.osv):
def _amount_line(self, cr, uid, ids, field_name, arg, context): def _amount_line(self, cr, uid, ids, field_name, arg, context):
res = {} res = {}
cur_obj=self.pool.get('res.currency') cur_obj = self.pool.get('res.currency')
for line in self.browse(cr, uid, ids): for line in self.browse(cr, uid, ids):
res[line.id] = line.price_unit * line.product_uom_qty * (1 - (line.discount or 0.0) / 100.0) res[line.id] = line.price_unit * line.product_uom_qty * (1 - (line.discount or 0.0) / 100.0)
cur = line.order_id.pricelist_id.currency_id cur = line.order_id.pricelist_id.currency_id
@ -709,28 +724,28 @@ class sale_order_line(osv.osv):
'name': fields.char('Description', size=256, required=True, select=True), 'name': fields.char('Description', size=256, required=True, select=True),
'sequence': fields.integer('Sequence'), 'sequence': fields.integer('Sequence'),
'delay': fields.float('Delivery Delay', required=True), 'delay': fields.float('Delivery Delay', required=True),
'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok','=',True)], change_default=True), 'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], change_default=True),
'invoice_lines': fields.many2many('account.invoice.line', 'sale_order_line_invoice_rel', 'order_line_id','invoice_id', 'Invoice Lines', readonly=True), 'invoice_lines': fields.many2many('account.invoice.line', 'sale_order_line_invoice_rel', 'order_line_id', 'invoice_id', 'Invoice Lines', readonly=True),
'invoiced': fields.boolean('Invoiced', readonly=True), 'invoiced': fields.boolean('Invoiced', readonly=True),
'procurement_id': fields.many2one('mrp.procurement', 'Procurement'), 'procurement_id': fields.many2one('mrp.procurement', 'Procurement'),
'price_unit': fields.float('Unit Price', required=True, digits=(16, int(config['price_accuracy']))), 'price_unit': fields.float('Unit Price', required=True, digits=(16, int(config['price_accuracy']))),
'price_net': fields.function(_amount_line_net, method=True, string='Net Price', digits=(16, int(config['price_accuracy']))), 'price_net': fields.function(_amount_line_net, method=True, string='Net Price', digits=(16, int(config['price_accuracy']))),
'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal'), 'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal'),
'tax_id': fields.many2many('account.tax', 'sale_order_tax', 'order_line_id', 'tax_id', 'Taxes'), 'tax_id': fields.many2many('account.tax', 'sale_order_tax', 'order_line_id', 'tax_id', 'Taxes'),
'type': fields.selection([('make_to_stock','from stock'),('make_to_order','on order')],'Procure Method', required=True), 'type': fields.selection([('make_to_stock', 'from stock'), ('make_to_order', 'on order')], 'Procure Method', required=True),
'property_ids': fields.many2many('mrp.property', 'sale_order_line_property_rel', 'order_id', 'property_id', 'Properties'), 'property_ids': fields.many2many('mrp.property', 'sale_order_line_property_rel', 'order_id', 'property_id', 'Properties'),
'address_allotment_id' : fields.many2one('res.partner.address', 'Allotment Partner'), 'address_allotment_id': fields.many2one('res.partner.address', 'Allotment Partner'),
'product_uom_qty': fields.float('Quantity (UoM)', digits=(16,2), required=True), 'product_uom_qty': fields.float('Quantity (UoM)', digits=(16, 2), required=True),
'product_uom': fields.many2one('product.uom', 'Product UoM', required=True), 'product_uom': fields.many2one('product.uom', 'Product UoM', required=True),
'product_uos_qty': fields.float('Quantity (UoS)'), 'product_uos_qty': fields.float('Quantity (UoS)'),
'product_uos': fields.many2one('product.uom', 'Product UoS'), 'product_uos': fields.many2one('product.uom', 'Product UoS'),
'product_packaging': fields.many2one('product.packaging', 'Packaging'), 'product_packaging': fields.many2one('product.packaging', 'Packaging'),
'move_ids': fields.one2many('stock.move', 'sale_line_id', 'Inventory Moves', readonly=True), 'move_ids': fields.one2many('stock.move', 'sale_line_id', 'Inventory Moves', readonly=True),
'discount': fields.float('Discount (%)', digits=(16,2)), 'discount': fields.float('Discount (%)', digits=(16, 2)),
'number_packages': fields.function(_number_packages, method=True, type='integer', string='Number Packages'), 'number_packages': fields.function(_number_packages, method=True, type='integer', string='Number Packages'),
'notes': fields.text('Notes'), 'notes': fields.text('Notes'),
'th_weight' : fields.float('Weight'), 'th_weight': fields.float('Weight'),
'state': fields.selection([('draft','Draft'),('confirmed','Confirmed'),('done','Done'),('cancel','Cancelled'),('exception','Exception')], 'Status', required=True, readonly=True), 'state': fields.selection([('draft', 'Draft'), ('confirmed', 'Confirmed'), ('done', 'Done'), ('cancel', 'Cancelled'), ('exception', 'Exception')], 'Status', required=True, readonly=True),
'order_partner_id': fields.related('order_id', 'partner_id', type='many2one', relation='res.partner', string='Customer') 'order_partner_id': fields.related('order_id', 'partner_id', type='many2one', relation='res.partner', string='Customer')
} }
_order = 'sequence, id' _order = 'sequence, id'
@ -745,6 +760,7 @@ class sale_order_line(osv.osv):
'type': lambda *a: 'make_to_stock', 'type': lambda *a: 'make_to_stock',
'product_packaging': lambda *a: False 'product_packaging': lambda *a: False
} }
def invoice_line_create(self, cr, uid, ids, context={}): def invoice_line_create(self, cr, uid, ids, context={}):
def _get_line_qty(line): def _get_line_qty(line):
if (line.order_id.invoice_quantity=='order') or not line.procurement_id: if (line.order_id.invoice_quantity=='order') or not line.procurement_id:
@ -769,7 +785,7 @@ class sale_order_line(osv.osv):
for line in self.browse(cr, uid, ids, context): for line in self.browse(cr, uid, ids, context):
if not line.invoiced: if not line.invoiced:
if line.product_id: if line.product_id:
a = line.product_id.product_tmpl_id.property_account_income.id a = line.product_id.product_tmpl_id.property_account_income.id
if not a: if not a:
a = line.product_id.categ_id.property_account_income_categ.id a = line.product_id.categ_id.property_account_income_categ.id
if not a: if not a:
@ -791,19 +807,19 @@ class sale_order_line(osv.osv):
a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, a) a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, a)
inv_id = self.pool.get('account.invoice.line').create(cr, uid, { inv_id = self.pool.get('account.invoice.line').create(cr, uid, {
'name': line.name, 'name': line.name,
'origin':line.order_id.name, 'origin': line.order_id.name,
'account_id': a, 'account_id': a,
'price_unit': pu, 'price_unit': pu,
'quantity': uosqty, 'quantity': uosqty,
'discount': line.discount, 'discount': line.discount,
'uos_id': uos_id, 'uos_id': uos_id,
'product_id': line.product_id.id or False, 'product_id': line.product_id.id or False,
'invoice_line_tax_id': [(6,0,[x.id for x in line.tax_id])], 'invoice_line_tax_id': [(6, 0, [x.id for x in line.tax_id])],
'note': line.notes, 'note': line.notes,
'account_analytic_id': line.order_id.project_id.id, 'account_analytic_id': line.order_id.project_id.id,
}) })
cr.execute('insert into sale_order_line_invoice_rel (order_line_id,invoice_id) values (%s,%s)', (line.id, inv_id)) cr.execute('insert into sale_order_line_invoice_rel (order_line_id,invoice_id) values (%s,%s)', (line.id, inv_id))
self.write(cr, uid, [line.id], {'invoiced':True}) self.write(cr, uid, [line.id], {'invoiced': True})
sales[line.order_id.id] = True sales[line.order_id.id] = True
create_ids.append(inv_id) create_ids.append(inv_id)
@ -818,15 +834,15 @@ class sale_order_line(osv.osv):
for line in self.browse(cr, uid, ids, context=context): for line in self.browse(cr, uid, ids, context=context):
if line.invoiced: if line.invoiced:
raise osv.except_osv(_('Invalid action !'), _('You cannot cancel a sale order line that has already been invoiced !')) raise osv.except_osv(_('Invalid action !'), _('You cannot cancel a sale order line that has already been invoiced !'))
return self.write(cr, uid, ids, {'state':'cancel'}) return self.write(cr, uid, ids, {'state': 'cancel'})
def button_confirm(self, cr, uid, ids, context={}): def button_confirm(self, cr, uid, ids, context={}):
return self.write(cr, uid, ids, {'state':'confirmed'}) return self.write(cr, uid, ids, {'state': 'confirmed'})
def button_done(self, cr, uid, ids, context={}): def button_done(self, cr, uid, ids, context={}):
wf_service = netsvc.LocalService("workflow") wf_service = netsvc.LocalService("workflow")
res = self.write(cr, uid, ids, {'state':'done'}) res = self.write(cr, uid, ids, {'state': 'done'})
for line in self.browse(cr,uid,ids,context): for line in self.browse(cr, uid, ids, context):
wf_service.trg_write(uid, 'sale.order', line.order_id.id, cr) wf_service.trg_write(uid, 'sale.order', line.order_id.id, cr)
return res return res
@ -835,26 +851,26 @@ class sale_order_line(osv.osv):
product_obj = self.pool.get('product.product') product_obj = self.pool.get('product.product')
if not product_id: if not product_id:
return {'value': {'product_uom': product_uos, return {'value': {'product_uom': product_uos,
'product_uom_qty': product_uos_qty}, 'domain':{}} 'product_uom_qty': product_uos_qty}, 'domain': {}}
product = product_obj.browse(cr, uid, product_id) product = product_obj.browse(cr, uid, product_id)
value = { value = {
'product_uom' : product.uom_id.id, 'product_uom': product.uom_id.id,
} }
# FIXME must depend on uos/uom of the product and not only of the coeff. # FIXME must depend on uos/uom of the product and not only of the coeff.
try: try:
value.update({ value.update({
'product_uom_qty' : product_uos_qty / product.uos_coeff, 'product_uom_qty': product_uos_qty / product.uos_coeff,
'th_weight' : product_uos_qty / product.uos_coeff * product.weight 'th_weight': product_uos_qty / product.uos_coeff * product.weight
}) })
except ZeroDivisionError: except ZeroDivisionError:
pass pass
return {'value' : value} return {'value': value}
def copy_data(self, cr, uid, id, default=None,context={}): def copy_data(self, cr, uid, id, default=None, context={}):
if not default: if not default:
default = {} default = {}
default.update({'state':'draft', 'move_ids':[], 'invoiced':False, 'invoice_lines':[]}) default.update({'state': 'draft', 'move_ids': [], 'invoiced': False, 'invoice_lines': []})
return super(sale_order_line, self).copy_data(cr, uid, id, default, context) return super(sale_order_line, self).copy_data(cr, uid, id, default, context)
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
@ -862,7 +878,7 @@ class sale_order_line(osv.osv):
lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False): lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False):
if not partner_id: if not partner_id:
raise osv.except_osv(_('No Customer Defined !'), _('You have to select a customer in the sale form !\nPlease set one customer before choosing a product.')) raise osv.except_osv(_('No Customer Defined !'), _('You have to select a customer in the sale form !\nPlease set one customer before choosing a product.'))
warning={} warning = {}
product_uom_obj = self.pool.get('product.uom') product_uom_obj = self.pool.get('product.uom')
partner_obj = self.pool.get('res.partner') partner_obj = self.pool.get('res.partner')
product_obj = self.pool.get('product.product') product_obj = self.pool.get('product.product')
@ -871,7 +887,7 @@ class sale_order_line(osv.osv):
context = {'lang': lang, 'partner_id': partner_id} context = {'lang': lang, 'partner_id': partner_id}
if not product: if not product:
return {'value': {'th_weight' : 0, 'product_packaging': False, return {'value': {'th_weight': 0, 'product_packaging': False,
'product_uos_qty': qty}, 'domain': {'product_uom': [], 'product_uos_qty': qty}, 'domain': {'product_uom': [],
'product_uos': []}} 'product_uos': []}}
@ -894,22 +910,22 @@ class sale_order_line(osv.osv):
qty_pack = pack.qty qty_pack = pack.qty
type_ul = pack.ul type_ul = pack.ul
warn_msg = _("You selected a quantity of %d Units.\nBut it's not compatible with the selected packaging.\nHere is a proposition of quantities according to the packaging: ") % (qty) warn_msg = _("You selected a quantity of %d Units.\nBut it's not compatible with the selected packaging.\nHere is a proposition of quantities according to the packaging: ") % (qty)
warn_msg = warn_msg + "\n\n"+_("EAN: ") + str(ean) + _(" Quantity: ") + str(qty_pack) + _(" Type of ul: ") + str(type_ul.name) warn_msg = warn_msg + "\n\n" + _("EAN: ") + str(ean) + _(" Quantity: ") + str(qty_pack) + _(" Type of ul: ") + str(type_ul.name)
warning={ warning = {
'title':_('Packing Information !'), 'title': _('Packing Information !'),
'message': warn_msg 'message': warn_msg
} }
result['product_uom_qty'] = qty result['product_uom_qty'] = qty
if uom: if uom:
uom2 = product_uom_obj.browse(cr, uid, uom) uom2 = product_uom_obj.browse(cr, uid, uom)
if product_obj.uom_id.category_id.id <> uom2.category_id.id: if product_obj.uom_id.category_id.id != uom2.category_id.id:
uom = False uom = False
if uos: if uos:
if product_obj.uos_id: if product_obj.uos_id:
uos2 = product_uom_obj.browse(cr, uid, uos) uos2 = product_uom_obj.browse(cr, uid, uos)
if product_obj.uos_id.category_id.id <> uos2.category_id.id: if product_obj.uos_id.category_id.id != uos2.category_id.id:
uos = False uos = False
else: else:
uos = False uos = False
@ -958,8 +974,8 @@ class sale_order_line(osv.osv):
# get unit price # get unit price
if not pricelist: if not pricelist:
warning={ warning = {
'title':'No Pricelist !', 'title': 'No Pricelist !',
'message': 'message':
'You have to select a pricelist in the sale form !\n' 'You have to select a pricelist in the sale form !\n'
'Please set one before choosing a product.' 'Please set one before choosing a product.'
@ -971,15 +987,15 @@ class sale_order_line(osv.osv):
'date': date_order, 'date': date_order,
})[pricelist] })[pricelist]
if price is False: if price is False:
warning={ warning = {
'title':'No valid pricelist line found !', 'title': 'No valid pricelist line found !',
'message': 'message':
"Couldn't find a pricelist line matching this product and quantity.\n" "Couldn't find a pricelist line matching this product and quantity.\n"
"You have to change either the product, the quantity or the pricelist." "You have to change either the product, the quantity or the pricelist."
} }
else: else:
result.update({'price_unit': price}) result.update({'price_unit': price})
return {'value': result, 'domain': domain,'warning':warning} return {'value': result, 'domain': domain, 'warning': warning}
def product_uom_change(self, cursor, user, ids, pricelist, product, qty=0, def product_uom_change(self, cursor, user, ids, pricelist, product, qty=0,
uom=False, qty_uos=0, uos=False, name='', partner_id=False, uom=False, qty_uos=0, uos=False, name='', partner_id=False,
@ -997,7 +1013,7 @@ class sale_order_line(osv.osv):
def unlink(self, cr, uid, ids, context={}): def unlink(self, cr, uid, ids, context={}):
"""Allows to delete sale order lines in draft,cancel states""" """Allows to delete sale order lines in draft,cancel states"""
for rec in self.browse(cr, uid, ids, context=context): for rec in self.browse(cr, uid, ids, context=context):
if rec.state not in ['draft','cancel']: if rec.state not in ['draft', 'cancel']:
raise osv.except_osv(_('Invalid action !'), _('Cannot delete a sale order line which is %s !')%(rec.state,)) raise osv.except_osv(_('Invalid action !'), _('Cannot delete a sale order line which is %s !')%(rec.state,))
return super(sale_order_line, self).unlink(cr, uid, ids, context=context) return super(sale_order_line, self).unlink(cr, uid, ids, context=context)
@ -1005,65 +1021,66 @@ sale_order_line()
class sale_config_picking_policy(osv.osv_memory): class sale_config_picking_policy(osv.osv_memory):
_name='sale.config.picking_policy' _name = 'sale.config.picking_policy'
_columns = { _columns = {
'name':fields.char('Name', size=64), 'name': fields.char('Name', size=64),
'picking_policy': fields.selection([ 'picking_policy': fields.selection([
('direct','Direct Delivery'), ('direct', 'Direct Delivery'),
('one','All at Once') ('one', 'All at Once')
], 'Packing Default Policy', required=True ), ], 'Packing Default Policy', required=True),
'order_policy': fields.selection([ 'order_policy': fields.selection([
('manual','Invoice Based on Sales Orders'), ('manual', 'Invoice Based on Sales Orders'),
('picking','Invoice Based on Deliveries'), ('picking', 'Invoice Based on Deliveries'),
], 'Shipping Default Policy', required=True), ], 'Shipping Default Policy', required=True),
'step': fields.selection([ 'step': fields.selection([
('one','Delivery Order Only'), ('one', 'Delivery Order Only'),
('two','Packing List & Delivery Order') ('two', 'Packing List & Delivery Order')
], 'Steps To Deliver a Sale Order', required=True, ], 'Steps To Deliver a Sale Order', required=True,
help="By default, Open ERP is able to manage complex routing and paths "\ help="By default, Open ERP is able to manage complex routing and paths "\
"of products in your warehouse and partner locations. This will configure "\ "of products in your warehouse and partner locations. This will configure "\
"the most common and simple methods to deliver products to the customer "\ "the most common and simple methods to deliver products to the customer "\
"in one or two operations by the worker.") "in one or two operations by the worker.")
} }
_defaults={ _defaults = {
'picking_policy': lambda *a: 'direct', 'picking_policy': lambda *a: 'direct',
'order_policy': lambda *a: 'picking', 'order_policy': lambda *a: 'picking',
'step': lambda *a: 'one' 'step': lambda *a: 'one'
} }
def set_default(self, cr, uid, ids, context=None): def set_default(self, cr, uid, ids, context=None):
for o in self.browse(cr, uid, ids, context=context): for o in self.browse(cr, uid, ids, context=context):
ir_values_obj = self.pool.get('ir.values') ir_values_obj = self.pool.get('ir.values')
ir_values_obj.set(cr,uid,'default',False,'picking_policy',['sale.order'],o.picking_policy) ir_values_obj.set(cr, uid, 'default', False, 'picking_policy', ['sale.order'], o.picking_policy)
ir_values_obj.set(cr,uid,'default',False,'order_policy',['sale.order'],o.order_policy) ir_values_obj.set(cr, uid, 'default', False, 'order_policy', ['sale.order'], o.order_policy)
if o.step=='one': if o.step == 'one':
md = self.pool.get('ir.model.data') md = self.pool.get('ir.model.data')
group_id = md._get_id(cr, uid, 'base', 'group_no_one') group_id = md._get_id(cr, uid, 'base', 'group_no_one')
group_id = md.browse(cr, uid, group_id, context).res_id group_id = md.browse(cr, uid, group_id, context).res_id
menu_id = md._get_id(cr, uid, 'stock', 'menu_action_picking_tree_delivery') menu_id = md._get_id(cr, uid, 'stock', 'menu_action_picking_tree_delivery')
menu_id = md.browse(cr, uid, menu_id, context).res_id menu_id = md.browse(cr, uid, menu_id, context).res_id
self.pool.get('ir.ui.menu').write(cr, uid, [menu_id], {'groups_id':[(6,0,[group_id])]}) self.pool.get('ir.ui.menu').write(cr, uid, [menu_id], {'groups_id': [(6, 0, [group_id])]})
location_id = md._get_id(cr, uid, 'stock', 'stock_location_output') location_id = md._get_id(cr, uid, 'stock', 'stock_location_output')
location_id = md.browse(cr, uid, location_id, context).res_id location_id = md.browse(cr, uid, location_id, context).res_id
self.pool.get('stock.location').write(cr, uid, [location_id], {'chained_auto_packing':'transparent'}) self.pool.get('stock.location').write(cr, uid, [location_id], {'chained_auto_packing': 'transparent'})
return { return {
'view_type': 'form', 'view_type': 'form',
"view_mode": 'form', "view_mode": 'form',
'res_model': 'ir.actions.configuration.wizard', 'res_model': 'ir.actions.configuration.wizard',
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
'target':'new', 'target': 'new',
} }
def action_cancel(self,cr,uid,ids,conect=None):
def action_cancel(self, cr, uid, ids, context=None):
return { return {
'view_type': 'form', 'view_type': 'form',
"view_mode": 'form', "view_mode": 'form',
'res_model': 'ir.actions.configuration.wizard', 'res_model': 'ir.actions.configuration.wizard',
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
'target':'new', 'target': 'new',
} }
sale_config_picking_policy() sale_config_picking_policy()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: