import ir
from mx import DateTime
import pooler
+from tools import config
#
# Model definition
return res
def _amount_untaxed(self, cr, uid, ids, field_name, arg, context):
- id_set = ",".join(map(str, ids))
- cr.execute("SELECT s.id,COALESCE(SUM(l.price_unit*l.product_qty),0)::decimal(16,2) AS amount FROM purchase_order s LEFT OUTER JOIN purchase_order_line l ON (s.id=l.order_id) WHERE s.id IN ("+id_set+") GROUP BY s.id ")
- res = dict(cr.fetchall())
+ res = {}
+ cur_obj=self.pool.get('res.currency')
+ for purchase in self.browse(cr, uid, ids):
+ res[purchase.id] = 0.0
+ for line in purchase.order_line:
+ res[purchase.id] += line.price_subtotal
+ cur = purchase.pricelist_id.currency_id
+ res[purchase.id] = cur_obj.round(cr, uid, cur, res[purchase.id])
+
return res
def _amount_tax(self, cr, uid, ids, field_name, arg, context):
res = {}
+ cur_obj=self.pool.get('res.currency')
for order in self.browse(cr, uid, ids):
val = 0.0
+ cur=order.pricelist_id.currency_id
for line in order.order_line:
- for tax in line.taxes_id:
- for c in self.pool.get('account.tax').compute(cr, uid, [tax.id], line.price_unit, line.product_qty, order.partner_address_id.id):
- val+=c['amount']
- res[order.id]=round(val,2)
+ for c in self.pool.get('account.tax').compute(cr, uid, line.taxes_id, line.price_unit, line.product_qty, order.partner_address_id.id, line.product_id, order.partner_id):
+ val+= cur_obj.round(cr, uid, cur, c['amount'])
+ res[order.id]=cur_obj.round(cr, uid, cur, val)
return res
def _amount_total(self, cr, uid, ids, field_name, arg, context):
res = {}
untax = self._amount_untaxed(cr, uid, ids, field_name, arg, context)
tax = self._amount_tax(cr, uid, ids, field_name, arg, context)
+ cur_obj=self.pool.get('res.currency')
for id in ids:
- res[id] = untax.get(id, 0.0) + tax.get(id, 0.0)
+ order=self.browse(cr, uid, [id])[0]
+ cur=order.pricelist_id.currency_id
+ res[id] = cur_obj.round(cr, uid, cur, untax.get(id, 0.0) + tax.get(id, 0.0))
return res
_columns = {
'name': fields.char('Order Description', size=64, required=True, select=True),
'origin': fields.char('Origin', size=64),
'ref': fields.char('Order Reference', size=64),
- 'partner_ref': fields.char('Partner Reference', size=64),
+ 'partner_ref': fields.char('Partner Ref.', size=64),
'date_order':fields.date('Date Ordered', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)]}),
'date_approve':fields.date('Date Approved'),
- 'partner_id':fields.many2one('res.partner', 'Partner', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)]}, change_default=True, relate=True),
+ 'partner_id':fields.many2one('res.partner', 'Partner', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)]}, change_default=True),
'partner_address_id':fields.many2one('res.partner.address', 'Address', required=True, states={'posted':[('readonly',True)]}),
'dest_address_id':fields.many2one('res.partner.address', 'Destination Address', states={'posted':[('readonly',True)]}),
- 'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', states={'posted':[('readonly',True)]}, relate=True),
+ 'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', states={'posted':[('readonly',True)]}),
'location_id': fields.many2one('stock.location', 'Delivery destination', required=True),
- 'project_id':fields.many2one('account.analytic.account', 'Analytic Account', states={'posted':[('readonly',True)]}),
'pricelist_id':fields.many2one('product.pricelist', 'Pricelist', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)]}),
- 'state': fields.selection([('draft', 'Request for Quotation'), ('wait', 'Waiting'), ('confirmed', 'Confirmed'), ('approved', 'Approved'),('except_ship', 'Shipping Exception'), ('except_invoice', 'Invoice Exception'), ('done', 'Done'), ('cancel', 'Cancelled')], 'Order State', readonly=True, help="The state of the purchase order or the quotation request. A quotation is a purchase order in a 'Draft' state. Then the order has to be confirmed by the user, the state switch to 'Confirmed'. Then the supplier must confirm the order to change the state to 'Approved'. When the purchase order is paid and received, the state becomes 'Done'. If a cancel action occurs in the invoice or in the reception of goods, the state becomes in exception.", select=True),
+ 'state': fields.selection([('draft', 'Request for Quotation'), ('wait', 'Waiting'), ('confirmed', 'Confirmed'), ('approved', 'Approved'),('except_picking', 'Shipping Exception'), ('except_invoice', 'Invoice Exception'), ('done', 'Done'), ('cancel', 'Cancelled')], 'Order State', readonly=True, help="The state of the purchase order or the quotation request. A quotation is a purchase order in a 'Draft' state. Then the order has to be confirmed by the user, the state switch to 'Confirmed'. Then the supplier must confirm the order to change the state to 'Approved'. When the purchase order is paid and received, the state becomes 'Done'. If a cancel action occurs in the invoice or in the reception of goods, the state becomes in exception.", select=True),
'order_line': fields.one2many('purchase.order.line', 'order_id', 'Order State', states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)]}),
'validator' : fields.many2one('res.users', 'Validated by', readonly=True),
'notes': fields.text('Notes'),
'invoice_id': fields.many2one('account.invoice', 'Invoice', readonly=True),
- 'picking_ids': fields.one2many('stock.picking', 'purchase_id', 'Picking List', readonly=True, help="This is the list of picking list that have been generated for this invoice"),
+ 'picking_ids': fields.one2many('stock.picking', 'purchase_id', 'Picking List', readonly=True, help="This is the list of picking list that have been generated for this purchase"),
'shipped':fields.boolean('Received', readonly=True, select=True),
'invoiced':fields.boolean('Invoiced & Paid', readonly=True, select=True),
- 'invoice_method': fields.selection([('manual','Manual'),('order','From order'),('picking','From picking')], 'Invoicing method', required=True),
+ 'invoice_method': fields.selection([('manual','Manual'),('order','From order'),('picking','From picking')], 'Invoicing Control', required=True),
'amount_untaxed': fields.function(_amount_untaxed, method=True, string='Untaxed Amount'),
'amount_tax': fields.function(_amount_tax, method=True, string='Taxes'),
'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'purchase.order'),
'shipped': lambda *a: 0,
'invoice_method': lambda *a: 'order',
- 'invoiced': lambda *a: 0
+ 'invoiced': lambda *a: 0,
+ 'partner_address_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').address_get(cr, uid, [context['partner_id']], ['default'])['default'],
+ 'pricelist_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').browse(cr, uid, context['partner_id']).property_product_pricelist_purchase.id,
}
_name = "purchase.order"
_description = "Purchase order"
+ _order = "name desc"
def button_dummy(self, cr, uid, ids, context={}):
return True
if not adr_id:
return {}
part_id = self.pool.get('res.partner.address').read(cr, uid, [adr_id], ['partner_id'])[0]['partner_id'][0]
- loc_id = self.pool.get('res.partner').browse(cr, uid, part_id).property_stock_customer[0]
+ loc_id = self.pool.get('res.partner').browse(cr, uid, part_id).property_stock_customer.id
return {'value':{'location_id': loc_id, 'warehouse_id': False}}
def onchange_warehouse_id(self, cr, uid, ids, warehouse_id):
if not part:
return {'value':{'partner_address_id': False}}
addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['default'])
- pricelist = self.pool.get('res.partner').browse(cr, uid, part).property_product_pricelist_purchase[0]
+ pricelist = self.pool.get('res.partner').browse(cr, uid, part).property_product_pricelist_purchase.id
return {'value':{'partner_address_id': addr['default'], 'pricelist_id': pricelist}}
def wkf_approve_order(self, cr, uid, ids):
'ref_partner_id': po.partner_id.id,
'ref_doc1': 'purchase.order,%d' % (po.id,),
})
+ def inv_line_create(self,a,ol):
+ return (0, False, {
+ 'name': ol.name,
+ 'account_id': a,
+ 'price_unit': ol.price_unit or 0.0,
+ 'quantity': ol.product_qty,
+ 'product_id': ol.product_id.id or False,
+ 'uos_id': ol.product_uom.id or False,
+ 'invoice_line_tax_id': [(6, 0, [x.id for x in ol.taxes_id])],
+ 'account_analytic_id': ol.account_analytic_id.id,
+ })
def action_invoice_create(self, cr, uid, ids, *args):
res = False
for ol in o.order_line:
if ol.product_id:
- a = ol.product_id.product_tmpl_id.property_account_expense
+ a = ol.product_id.product_tmpl_id.property_account_expense.id
+ if not a:
+ a = ol.product_id.categ_id.property_account_expense_categ.id
if not a:
- a = ol.product_id.categ_id.property_account_expense_categ[0]
- else:
- a = a[0]
+ raise osv.except_osv('Error !', 'There is no expense account defined for this product: "%s" (id:%d)' % (ol.product_id.name, ol.product_id.id,))
else:
a = self.pool.get('ir.property').get(cr, uid, 'property_account_expense_categ', 'product.category')
- il.append((0, False, {
- 'name': ol.name,
- 'account_id': a,
- 'price_unit': ol.price_unit or 0.0,
- 'quantity': ol.product_qty,
- 'product_id': ol.product_id.id or False,
- 'uos_id': ol.product_uom.id or False,
- 'invoice_line_tax_id': [(6, 0, [x.id for x in ol.taxes_id])]
- }))
+ il.append(self.inv_line_create(a,ol))
+# il.append((0, False, {
+# 'name': ol.name,
+# 'account_id': a,
+# 'price_unit': ol.price_unit or 0.0,
+# 'quantity': ol.product_qty,
+# 'product_id': ol.product_id.id or False,
+# 'uos_id': ol.product_uom.id or False,
+# 'invoice_line_tax_id': [(6, 0, [x.id for x in ol.taxes_id])],
+# 'account_analytic_id': ol.account_analytic_id.id,
+# }))
- a = o.partner_id.property_account_payable[0]
+ a = o.partner_id.property_account_payable.id
inv = {
- 'name': o.name,
+ 'name': o.partner_ref or o.name,
'reference': "P%dPO%d" % (o.partner_id.id, o.id),
'account_id': a,
'type': 'in_invoice',
'partner_id': o.partner_id.id,
'currency_id': o.pricelist_id.currency_id.id,
- 'project_id': o.project_id.id,
'address_invoice_id': o.partner_address_id.id,
'address_contact_id': o.partner_address_id.id,
'origin': o.name,
'invoice_line': il,
}
- inv_id = self.pool.get('account.invoice').create(cr, uid, inv)
+ inv_id = self.pool.get('account.invoice').create(cr, uid, inv, {'type':'in_invoice'})
+ self.pool.get('account.invoice').button_compute(cr, uid, [inv_id], {'type':'in_invoice'}, set_total=True)
self.write(cr, uid, [o.id], {'invoice_id': inv_id})
res = inv_id
def action_picking_create(self,cr, uid, ids, *args):
picking_id = False
for order in self.browse(cr, uid, ids):
- loc_id = order.partner_id.property_stock_supplier[0]
+ loc_id = order.partner_id.property_stock_supplier.id
istate = 'none'
if order.invoice_method=='picking':
istate = '2binvoiced'
'type': 'in',
'address_id': order.dest_address_id.id or order.partner_address_id.id,
'invoice_state': istate,
- 'purchase_id': order.id
+ 'purchase_id': order.id,
})
for order_line in order.order_line:
if not order_line.product_id:
'location_dest_id': dest,
'picking_id': picking_id,
'move_dest_id': order_line.move_dest_id.id,
- 'state': 'assigned'
+ 'state': 'assigned',
+ 'purchase_line_id': order_line.id,
})
if order_line.move_dest_id:
self.pool.get('stock.move').write(cr, uid, [order_line.move_dest_id.id], {'location_id':order.location_id.id})
class purchase_order_line(osv.osv):
def _amount_line(self, cr, uid, ids, prop, unknow_none,unknow_dict):
res = {}
+ cur_obj=self.pool.get('res.currency')
for line in self.browse(cr, uid, ids):
- res[line.id] = line.price_unit * line.product_qty
+ cur = line.order_id.pricelist_id.currency_id
+ res[line.id] = cur_obj.round(cr, uid, cur, line.price_unit * line.product_qty)
return res
_columns = {
'name': fields.char('Description', size=64, required=True),
'product_qty': fields.float('Quantity', required=True, digits=(16,2)),
- 'date_planned': fields.date('Date Promised', required=True),
+ 'date_planned': fields.date('Scheduled date', required=True),
'taxes_id': fields.many2many('account.tax', 'purchase_order_taxe', 'ord_id', 'tax_id', 'Taxes'),
'product_uom': fields.many2one('product.uom', 'Product UOM', required=True),
- 'product_id': fields.many2one('product.product', 'Product', domain=[('purchase_ok','=',True)], change_default=True, relate=True),
+ 'product_id': fields.many2one('product.product', 'Product', domain=[('purchase_ok','=',True)], change_default=True),
'move_id': fields.many2one('stock.move', 'Reservation', ondelete='set null'),
'move_dest_id': fields.many2one('stock.move', 'Reservation Destination', ondelete='set null'),
- 'price_unit': fields.float('Unit Price', required=True),
+ 'price_unit': fields.float('Unit Price', required=True, digits=(16, int(config['price_accuracy']))),
'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal'),
'notes': fields.text('Notes'),
- 'order_id': fields.many2one('purchase.order', 'Order Ref', select=True)
+ 'order_id': fields.many2one('purchase.order', 'Order Ref', select=True, required=True, ondelete='cascade'),
+ 'account_analytic_id':fields.many2one('account.analytic.account', 'Analytic Account',),
}
_defaults = {
'product_qty': lambda *a: 1.0
default.update({'state':'draft', 'move_id':False})
return super(purchase_order_line, self).copy(cr, uid, id, default, context)
- def product_id_change(self, cr, uid, ids, pricelist, product, qty, uom, partner_id):
+ def product_id_change(self, cr, uid, ids, pricelist, product, qty, uom,
+ partner_id, date_order=False):
if not pricelist:
- raise osv.except_osv('No Pricelist !', 'You have to select a pricelist in the sale form !\n Please set one before choosing a product.')
+ raise osv.except_osv('No Pricelist !', 'You have to select a pricelist in the purchase form !\n Please set one before choosing a product.')
if not product:
return {'value': {'price_unit': 0.0, 'name':'','notes':''}, 'domain':{'product_uom':[]}}
- price = self.pool.get('product.pricelist').price_get(cr,uid,[pricelist], product, qty or 1.0, partner_id, {'uom': uom})[pricelist]
- prod = self.pool.get('product.product').read(cr, uid, [product], ['taxes_id','name','seller_delay','uom_po_id','description_purchase'])[0]
+ lang=False
+ if partner_id:
+ lang=self.pool.get('res.partner').read(cr, uid, [partner_id])[0]['lang']
+ context={'lang':lang}
+
+ prod = self.pool.get('product.product').read(cr, uid, [product], ['supplier_taxes_id','name','seller_delay','uom_po_id','description_purchase'])[0]
+ prod_uom_po = prod['uom_po_id'][0]
+ if not uom:
+ uom = prod_uom_po
+ if not date_order:
+ date_order = time.strftime('%Y-%m-%d')
+ price = self.pool.get('product.pricelist').price_get(cr,uid,[pricelist],
+ product, qty or 1.0, partner_id, {
+ 'uom': uom,
+ 'date': date_order,
+ })[pricelist]
dt = (DateTime.now() + DateTime.RelativeDateTime(days=prod['seller_delay'] or 0.0)).strftime('%Y-%m-%d')
- prod_name = self.pool.get('product.product').name_get(cr, uid, [product])[0][1]
- res = {'value': {'price_unit': price, 'name':prod_name, 'taxes_id':prod['taxes_id'], 'date_planned': dt,'notes':prod['description_purchase']}}
+ prod_name = self.pool.get('product.product').name_get(cr, uid, [product], context=context)[0][1]
+
+ res = {'value': {'price_unit': price, 'name':prod_name, 'taxes_id':prod['supplier_taxes_id'], 'date_planned': dt,'notes':prod['description_purchase'], 'product_uom': uom}}
domain = {}
- if not uom:
- res['value']['product_uom'] = prod['uom_po_id'][0]
- if res['value']['product_uom']:
- res2 = self.pool.get('product.uom').read(cr, uid, [res['value']['product_uom']], ['category_id'])
- if res2 and res2[0]['category_id']:
- domain = {'product_uom':[('category_id','=',res2[0]['category_id'][0])]}
+
+ res2 = self.pool.get('product.uom').read(cr, uid, [uom], ['category_id'])
+ res3 = self.pool.get('product.uom').read(cr, uid, [prod_uom_po], ['category_id'])
+ domain = {'product_uom':[('category_id','=',res2[0]['category_id'][0])]}
+ if res2[0]['category_id'] != res3[0]['category_id']:
+ raise osv.except_osv('Wrong Product UOM !', 'You have to select a product UOM in the same category than the purchase UOM of the product')
+
res['domain'] = domain
return res
+
+ def product_uom_change(self, cr, uid, ids, pricelist, product, qty, uom,
+ partner_id, date_order=False):
+ res = self.product_id_change(cr, uid, ids, pricelist, product, qty, uom,
+ partner_id, date_order=date_order)
+ if 'product_uom' in res['value']:
+ del res['value']['product_uom']
+ if not uom:
+ res['value']['price_unit'] = 0.0
+ return res
purchase_order_line()