##############################################################################
import time
+import pytz
+from openerp import SUPERUSER_ID
from datetime import datetime
from dateutil.relativedelta import relativedelta
]
_track = {
'state': {
- 'purchase.mt_rfq_confirmed': lambda self, cr, uid, obj, ctx=None: obj['state']=='confirmed',
- 'purchase.mt_rfq_approved': lambda self, cr, uid, obj, ctx=None: obj['state']=='approved',
+ 'purchase.mt_rfq_confirmed': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'confirmed',
+ 'purchase.mt_rfq_approved': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'approved',
},
}
_columns = {
'name': fields.char('Order Reference', size=64, required=True, select=True, help="Unique number of the purchase order, computed automatically when the purchase order is created."),
'origin': fields.char('Source Document', size=64,
- help="Reference of the document that generated this purchase order request; a sale order or an internal procurement request."
+ help="Reference of the document that generated this purchase order request; a sales order or an internal procurement request."
),
'partner_ref': fields.char('Supplier Reference', states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}, size=64,
- help="Reference of the sale order or quotation sent by your supplier. It's mainly used to do the matching when you receive the products as this reference is usually written on the delivery order sent by your supplier."),
+ help="Reference of the sales order or quotation sent by your supplier. It's mainly used to do the matching when you receive the products as this reference is usually written on the delivery order sent by your supplier."),
'date_order':fields.date('Order Date', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)]}, select=True, help="Date on which this document has been created."),
'date_approve':fields.date('Date Approved', readonly=1, select=True, help="Date on which purchase order has been approved"),
'partner_id':fields.many2one('res.partner', 'Supplier', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]},
- change_default=True, track_visibility=2),
+ change_default=True, track_visibility='always'),
'dest_address_id':fields.many2one('res.partner', 'Customer Address (Direct Delivery)',
states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]},
help="Put an address if you want to deliver directly from the supplier to the customer. " \
'amount_untaxed': fields.function(_amount_all, digits_compute= dp.get_precision('Account'), string='Untaxed Amount',
store={
'purchase.order.line': (_get_order, None, 10),
- }, multi="sums", help="The amount without tax", track_visibility=2),
+ }, multi="sums", help="The amount without tax", track_visibility='always'),
'amount_tax': fields.function(_amount_all, digits_compute= dp.get_precision('Account'), string='Taxes',
store={
'purchase.order.line': (_get_order, None, 10),
def view_invoice(self, cr, uid, ids, context=None):
'''
- This function returns an action that display existing invoices of given sale order ids. It can either be a in a list or in a form view, if there is only one invoice to show.
+ This function returns an action that display existing invoices of given sales order ids. It can either be a in a list or in a form view, if there is only one invoice to show.
'''
mod_obj = self.pool.get('ir.model.data')
wizard_obj = self.pool.get('purchase.order.line_invoice')
self.write(cr, uid, [id], {'state' : 'confirmed', 'validator' : uid})
return True
+ def _choose_account_from_po_line(self, cr, uid, po_line, context=None):
+ fiscal_obj = self.pool.get('account.fiscal.position')
+ property_obj = self.pool.get('ir.property')
+ if po_line.product_id:
+ acc_id = po_line.product_id.property_account_expense.id
+ if not acc_id:
+ acc_id = po_line.product_id.categ_id.property_account_expense_categ.id
+ if not acc_id:
+ raise osv.except_osv(_('Error!'), _('Define expense account for this company: "%s" (id:%d).') % (po_line.product_id.name, po_line.product_id.id,))
+ else:
+ acc_id = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category').id
+ fpos = po_line.order_id.fiscal_position or False
+ return fiscal_obj.map_account(cr, uid, fpos, acc_id)
+
def _prepare_inv_line(self, cr, uid, account_id, order_line, context=None):
"""Collects require data from purchase order line that is used to create invoice line
for that purchase order line
journal_obj = self.pool.get('account.journal')
inv_obj = self.pool.get('account.invoice')
inv_line_obj = self.pool.get('account.invoice.line')
- fiscal_obj = self.pool.get('account.fiscal.position')
- property_obj = self.pool.get('ir.property')
for order in self.browse(cr, uid, ids, context=context):
pay_acc_id = order.partner_id.property_account_payable.id
# generate invoice line correspond to PO line and link that to created invoice (inv_id) and PO line
inv_lines = []
for po_line in order.order_line:
- if po_line.product_id:
- acc_id = po_line.product_id.product_tmpl_id.property_account_expense.id
- if not acc_id:
- acc_id = po_line.product_id.categ_id.property_account_expense_categ.id
- if not acc_id:
- raise osv.except_osv(_('Error!'), _('Define expense account for this company: "%s" (id:%d).') % (po_line.product_id.name, po_line.product_id.id,))
- else:
- acc_id = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category').id
- fpos = order.fiscal_position or False
- acc_id = fiscal_obj.map_account(cr, uid, fpos, acc_id)
-
+ acc_id = self._choose_account_from_po_line(cr, uid, po_line, context=context)
inv_line_data = self._prepare_inv_line(cr, uid, acc_id, po_line, context=context)
inv_line_id = inv_line_obj.create(cr, uid, inv_line_data, context=context)
inv_lines.append(inv_line_id)
def has_stockable_product(self, cr, uid, ids, *args):
for order in self.browse(cr, uid, ids):
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.type in ('product', 'consu'):
return True
return False
wf_service.trg_validate(uid, 'purchase.order', id, 'purchase_cancel', cr)
return True
+ def date_to_datetime(self, cr, uid, userdate, context=None):
+ """ Convert date values expressed in user's timezone to
+ server-side UTC timestamp, assuming a default arbitrary
+ time of 12:00 AM - because a time is needed.
+
+ :param str userdate: date string in in user time zone
+ :return: UTC datetime string for server-side use
+ """
+ # TODO: move to fields.datetime in server after 7.0
+ user_date = datetime.strptime(userdate, DEFAULT_SERVER_DATE_FORMAT)
+ if context and context.get('tz'):
+ tz_name = context['tz']
+ else:
+ tz_name = self.pool.get('res.users').read(cr, SUPERUSER_ID, uid, ['tz'])['tz']
+ if tz_name:
+ utc = pytz.timezone('UTC')
+ context_tz = pytz.timezone(tz_name)
+ user_datetime = user_date + relativedelta(hours=12.0)
+ local_timestamp = context_tz.localize(user_datetime, is_dst=False)
+ user_datetime = local_timestamp.astimezone(utc)
+ return user_datetime.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
+ return user_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
+
def _prepare_order_picking(self, cr, uid, order, context=None):
return {
'name': self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.in'),
'origin': order.name + ((order.origin and (':' + order.origin)) or ''),
- 'date': order.date_order,
+ 'date': self.date_to_datetime(cr, uid, order.date_order, context),
'partner_id': order.dest_address_id.id or order.partner_id.id,
'invoice_state': '2binvoiced' if order.invoice_method == 'picking' else 'none',
'type': 'in',
'product_uos_qty': order_line.product_qty,
'product_uom': order_line.product_uom.id,
'product_uos': order_line.product_uom.id,
- 'date': order_line.date_planned,
- 'date_expected': order_line.date_planned,
+ 'date': self.date_to_datetime(cr, uid, order.date_order, context),
+ 'date_expected': self.date_to_datetime(cr, uid, order_line.date_planned, context),
'location_id': order.partner_id.property_stock_supplier.id,
'location_dest_id': order.location_id.id,
'picking_id': picking_id,
wf_service.trg_validate(uid, 'purchase.order', old_id, 'purchase_cancel', cr)
return orders_info
- # --------------------------------------
- # OpenChatter methods and notifications
- # --------------------------------------
-
- def needaction_domain_get(self, cr, uid, ids, context=None):
- return [('state', '=', 'draft')]
-
class purchase_order_line(osv.osv):
def _amount_line(self, cr, uid, ids, prop, arg, context=None):
lang = res_partner.browse(cr, uid, partner_id).lang
context_partner.update( {'lang': lang, 'partner_id': partner_id} )
product = product_product.browse(cr, uid, product_id, context=context_partner)
- name = product.name
+ #call name_get() with partner in the context to eventually match name and description in the seller_ids field
+ dummy, name = product_product.name_get(cr, uid, product_id, context=context_partner)[0]
if product.description_purchase:
name += '\n' + product.description_purchase
res['value'].update({'name': name})
'''
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
for procurement in self.browse(cr, uid, ids, context=context):
- if procurement.product_id.product_tmpl_id.supply_method <> 'buy':
+ if procurement.product_id.supply_method <> 'buy':
return False
return True
partner_obj = self.pool.get('res.partner')
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
for procurement in self.browse(cr, uid, ids, context=context):
- if not procurement.product_id.seller_ids:
- message = _('No supplier defined for this product !')
- self.message_post(cr, uid, [procurement.id], body=message)
- cr.execute('update procurement_order set message=%s where id=%s', (message, procurement.id))
- return False
+ message = ''
partner = procurement.product_id.seller_id #Taken Main Supplier of Product of Procurement.
- if not partner:
+ if not procurement.product_id.seller_ids:
+ message = _('No supplier defined for this product !')
+ elif not partner:
message = _('No default supplier defined for this product')
- self.message_post(cr, uid, [procurement.id], body=message)
- cr.execute('update procurement_order set message=%s where id=%s', (message, procurement.id))
+ elif not partner_obj.address_get(cr, uid, [partner.id], ['delivery'])['delivery']:
+ message = _('No address defined for the supplier')
+
+ if message:
+ if procurement.message != message:
+ # avoid sending too many messages
+ self.message_post(cr, uid, [procurement.id], body=message)
+ self.write(cr, uid, [procurement.id], {'message':message}, context=context)
return False
+
if user.company_id and user.company_id.partner_id:
if partner.id == user.company_id.partner_id.id:
raise osv.except_osv(_('Configuration Error!'), _('The product "%s" has been defined with your company as reseller which seems to be a configuration error!' % procurement.product_id.name))
- address_id = partner_obj.address_get(cr, uid, [partner.id], ['delivery'])['delivery']
- if not address_id:
- message = _('No address defined for the supplier')
- self.message_post(cr, uid, [procurement.id], body=message)
- cr.execute('update procurement_order set message=%s where id=%s', (message, procurement.id))
- return False
return True
new_context.update({'lang': partner.lang, 'partner_id': partner_id})
product = prod_obj.browse(cr, uid, procurement.product_id.id, context=new_context)
- taxes_ids = procurement.product_id.product_tmpl_id.supplier_taxes_id
+ taxes_ids = procurement.product_id.supplier_taxes_id
taxes = acc_pos_obj.map_tax(cr, uid, partner.property_account_position, taxes_ids)
name = product.partner_ref
}
res[procurement.id] = self.create_procurement_purchase_order(cr, uid, procurement, po_vals, line_vals, context=new_context)
self.write(cr, uid, [procurement.id], {'state': 'running', 'purchase_id': res[procurement.id]})
- self.purchase_order_create_note(cr, uid, ids, context=context)
+ self.message_post(cr, uid, ids, body=_("Draft Purchase Order created"), context=context)
return res
-
+
def _product_virtual_get(self, cr, uid, order_point):
procurement = order_point.procurement_id
if procurement and procurement.state != 'exception' and procurement.purchase_id and procurement.purchase_id.state in ('draft', 'confirmed'):
return None
return super(procurement_order, self)._product_virtual_get(cr, uid, order_point)
- def purchase_order_create_note(self, cr, uid, ids, context=None):
- for procurement in self.browse(cr, uid, ids, context=context):
- body = _("Draft Purchase Order created")
- self.message_post(cr, uid, [procurement.id], body=body, context=context)
-
-procurement_order()
-class mail_mail(osv.osv):
+class mail_mail(osv.Model):
_name = 'mail.mail'
_inherit = 'mail.mail'
wf_service.trg_validate(uid, 'purchase.order', mail.res_id, 'send_rfq', cr)
return super(mail_mail, self)._postprocess_sent_message(cr, uid, mail=mail, context=context)
-mail_mail()
-class product_template(osv.osv):
+class product_template(osv.Model):
_name = 'product.template'
_inherit = 'product.template'
_columns = {
'purchase_ok': 1,
}
-product_template()
-class mail_compose_message(osv.osv):
+class mail_compose_message(osv.Model):
_inherit = 'mail.compose.message'
+
def send_mail(self, cr, uid, ids, context=None):
context = context or {}
if context.get('default_model') == 'purchase.order' and context.get('default_res_id'):
+ context = dict(context, mail_post_autofollow=True)
wf_service = netsvc.LocalService("workflow")
wf_service.trg_validate(uid, 'purchase.order', context['default_res_id'], 'send_rfq', cr)
return super(mail_compose_message, self).send_mail(cr, uid, ids, context=context)