_name = "sale.order"
_inherit = ['ir.needaction_mixin', 'mail.thread']
_description = "Sales Order"
-
+
def copy(self, cr, uid, id, default=None, context=None):
if not default:
fnct_search=_invoiced_search, type='boolean', help="It indicates that an invoice has been paid."),
'note': fields.text('Terms and conditions'),
- 'amount_untaxed': fields.function(_amount_all, digits_compute= dp.get_precision('Sale Price'), string='Untaxed Amount',
+ 'amount_untaxed': fields.function(_amount_all, digits_compute= dp.get_precision('Account'), string='Untaxed Amount',
store = {
'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),
},
multi='sums', help="The amount without tax."),
- 'amount_tax': fields.function(_amount_all, digits_compute= dp.get_precision('Sale Price'), string='Taxes',
+ 'amount_tax': fields.function(_amount_all, digits_compute= dp.get_precision('Account'), string='Taxes',
store = {
'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),
},
multi='sums', help="The tax amount."),
- 'amount_total': fields.function(_amount_all, digits_compute= dp.get_precision('Sale Price'), string='Total',
+ 'amount_total': fields.function(_amount_all, digits_compute= dp.get_precision('Account'), string='Total',
store = {
'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),
if s['state'] in ['draft', 'cancel']:
unlink_ids.append(s['id'])
else:
- raise osv.except_osv(_('Invalid action !'), _('In order to delete a confirmed sale order, you must cancel it before ! To cancel a sale order, you must first cancel related picking or delivery orders.'))
+ raise osv.except_osv(_('Invalid Action!'), _('In order to delete a confirmed sales order, you must cancel it.\nTo do so, you must first cancel related picking for delivery orders.'))
return osv.osv.unlink(self, cr, uid, unlink_ids, context=context)
[('type', '=', 'sale'), ('company_id', '=', order.company_id.id)],
limit=1)
if not journal_ids:
- raise osv.except_osv(_('Error !'),
- _('There is no sales journal defined for this company: "%s" (id:%d)') % (order.company_id.name, order.company_id.id))
+ raise osv.except_osv(_('Error!'),
+ _('Please define sales journal for this company: "%s" (id:%d).') % (order.company_id.name, order.company_id.id))
invoice_vals = {
'name': order.client_order_ref or '',
'form': self.read(cr, uid, ids[0], context=context),
}
return {'type': 'ir.actions.report.xml', 'report_name': 'sale.order', 'datas': datas, 'nodestroy': True}
-
+
def manual_invoice(self, cr, uid, ids, context=None):
""" create invoices for the given sale orders (ids), and open the form
view of one of the newly created invoices
result.update(view_id = res and res[1] or False)
return result
-
+
def action_view_delivery(self, cr, uid, ids, context=None):
'''
This function returns an action that display existing delivery orders of given sale order ids. It can either be a in a list or in a form view, if there is only one delivery order to show.
currency_id = o.pricelist_id.currency_id.id
if (o.partner_id.id in partner_currency) and (partner_currency[o.partner_id.id] <> currency_id):
raise osv.except_osv(
- _('Error !'),
+ _('Error!'),
_('You cannot group sales having different currencies for the same partner.'))
partner_currency[o.partner_id.id] = currency_id
for pick in sale.picking_ids:
if pick.state not in ('draft', 'cancel'):
raise osv.except_osv(
- _('Could not cancel sales order !'),
- _('You must first cancel all picking attached to this sales order.'))
+ _('Cannot cancel sales order!'),
+ _('You must first cancel all delivery order(s) attached to this sales order.'))
if pick.state == 'cancel':
for mov in pick.move_lines:
proc_ids = proc_obj.search(cr, uid, [('move_id', '=', mov.id)])
for inv in sale.invoice_ids:
if inv.state not in ('draft', 'cancel'):
raise osv.except_osv(
- _('Could not cancel this sales order !'),
- _('You must first cancel all invoices attached to this sales order.'))
+ _('Cannot cancel this sales order!'),
+ _('First cancel all invoices attached to this sales order.'))
for r in self.read(cr, uid, ids, ['invoice_ids']):
for inv in r['invoice_ids']:
wf_service.trg_validate(uid, 'account.invoice', inv, 'invoice_cancel', cr)
return True
def action_button_confirm(self, cr, uid, ids, context=None):
- assert len(ids) == 1, 'This option should only be used for a single id at a time'
+ assert len(ids) == 1, 'This option should only be used for a single id at a time.'
wf_service = netsvc.LocalService('workflow')
wf_service.trg_validate(uid, 'sale.order', ids[0], 'order_confirm', cr)
def action_wait(self, cr, uid, ids, context=None):
for o in self.browse(cr, uid, ids):
if not o.order_line:
- raise osv.except_osv(_('Error !'),_('You cannot confirm a sale order which has no line.'))
+ raise osv.except_osv(_('Error!'),_('You cannot confirm a sale order which has no line.'))
if (o.order_policy == 'manual'):
self.write(cr, uid, [o.id], {'state': 'manual', 'date_confirm': fields.date.context_today(self, cr, uid, context=context)})
else:
'''
This function opens a window to compose an email, with the edi sale template message loaded by default
'''
- assert len(ids) == 1, 'This option should only be used for a single id at a time'
+ assert len(ids) == 1, 'This option should only be used for a single id at a time.'
mod_obj = self.pool.get('ir.model.data')
template = mod_obj.get_object_reference(cr, uid, 'sale', 'email_template_edi_sale')
template_id = template and template[1] or False
'procure_method': line.type,
'move_id': move_id,
'company_id': order.company_id.id,
- 'note': '\n'.join(line.name.split('\n')[1:]),
- 'property_ids': [(6, 0, [x.id for x in line.property_ids])]
+ 'note': '\n'.join(line.name.split('\n')[1:])
}
def _prepare_order_line_move(self, cr, uid, order, line, picking_id, date_planned, context=None):
# ------------------------------------------------
# OpenChatter methods and notifications
# ------------------------------------------------
-
+
def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = super(sale_order, self).get_needaction_user_ids(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context):
if (obj.state == 'manual' or obj.state == 'progress'):
result[obj.id].append(obj.user_id.id)
return result
-
+
def create_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
- self.message_subscribe(cr, uid, [obj.id], [obj.user_id.id], context=context)
self.message_append_note(cr, uid, [obj.id], body=_("Quotation for <em>%s</em> has been <b>created</b>.") % (obj.partner_id.name), context=context)
-
+
def confirm_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, [obj.id], body=_("Quotation for <em>%s</em> <b>converted</b> to Sale Order of %s %s.") % (obj.partner_id.name, obj.amount_total, obj.pricelist_id.currency_id.symbol), context=context)
-
+
def cancel_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, [obj.id], body=_("Sale Order for <em>%s</em> <b>cancelled</b>.") % (obj.partner_id.name), context=context)
-
+
def delivery_send_note(self, cr, uid, ids, picking_id, context=None):
for order in self.browse(cr, uid, ids, context=context):
for picking in (pck for pck in order.picking_ids if pck.id == picking_id):
picking_datetime = fields.DT.datetime.strptime(picking.min_date, DEFAULT_SERVER_DATETIME_FORMAT)
picking_date_str = fields.datetime.context_timestamp(cr, uid, picking_datetime, context=context).strftime(DATETIME_FORMATS_MAP['%+'] + " (%Z)")
self.message_append_note(cr, uid, [order.id], body=_("Delivery Order <em>%s</em> <b>scheduled</b> for %s.") % (picking.name, picking_date_str), context=context)
-
+
def delivery_end_send_note(self, cr, uid, ids, context=None):
self.message_append_note(cr, uid, ids, body=_("Order <b>delivered</b>."), context=context)
-
+
def invoice_paid_send_note(self, cr, uid, ids, context=None):
self.message_append_note(cr, uid, ids, body=_("Invoice <b>paid</b>."), context=context)
-
+
def invoice_send_note(self, cr, uid, ids, invoice_id, context=None):
for order in self.browse(cr, uid, ids, context=context):
for invoice in (inv for inv in order.invoice_ids if inv.id == invoice_id):
self.message_append_note(cr, uid, [order.id], body=_("Draft Invoice of %s %s <b>waiting for validation</b>.") % (invoice.amount_total, invoice.currency_id.symbol), context=context)
-
+
def action_cancel_draft_send_note(self, cr, uid, ids, context=None):
return self.message_append_note(cr, uid, ids, body='Sale order has been set in draft.', context=context)
-
-
+
+
sale_order()
# TODO add a field price_unit_uos
'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),
'procurement_id': fields.many2one('procurement.order', 'Procurement'),
- 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Sale Price'), readonly=True, states={'draft': [('readonly', False)]}),
- 'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Sale Price')),
+ 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price'), readonly=True, states={'draft': [('readonly', False)]}),
+ 'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')),
'tax_id': fields.many2many('account.tax', 'sale_order_tax', 'order_line_id', 'tax_id', 'Taxes', readonly=True, states={'draft': [('readonly', False)]}),
'type': fields.selection([('make_to_stock', 'from stock'), ('make_to_order', 'on order')], 'Procurement Method', required=True, readonly=True, states={'draft': [('readonly', False)]},
help="If 'on order', it triggers a procurement when the sale order is confirmed to create a task, purchase order or manufacturing order linked to this sale order line."),
'product_uos': fields.many2one('product.uom', 'Product UoS'),
'product_packaging': fields.many2one('product.packaging', 'Packaging'),
'move_ids': fields.one2many('stock.move', 'sale_line_id', 'Inventory Moves', readonly=True),
- 'discount': fields.float('Discount', digits=(16, 2), readonly=True, states={'draft': [('readonly', False)]}),
+ 'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount'), readonly=True, states={'draft': [('readonly', False)]}),
'number_packages': fields.function(_number_packages, type='integer', string='Number Packages'),
'th_weight': fields.float('Weight', readonly=True, states={'draft': [('readonly', False)]}),
'state': fields.selection([('cancel', 'Cancelled'),('draft', 'Draft'),('confirmed', 'Confirmed'),('exception', 'Exception'),('done', 'Done')], 'Status', required=True, readonly=True,
if not account_id:
account_id = line.product_id.categ_id.property_account_income_categ.id
if not account_id:
- raise osv.except_osv(_('Error !'),
- _('There is no income account defined for this product: "%s" (id:%d)') % \
+ raise osv.except_osv(_('Error!'),
+ _('Please define income account for this product: "%s" (id:%d).') % \
(line.product_id.name, line.product_id.id,))
else:
prop = self.pool.get('ir.property').get(cr, uid,
pu = 0.0
if uosqty:
pu = round(line.price_unit * line.product_uom_qty / uosqty,
- self.pool.get('decimal.precision').precision_get(cr, uid, 'Sale Price'))
+ self.pool.get('decimal.precision').precision_get(cr, uid, 'Product Price'))
fpos = line.order_id.fiscal_position or False
account_id = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, account_id)
if not account_id:
- raise osv.except_osv(_('Error !'),
- _('There is no income category account defined in default Properties for Product Category or Fiscal Position is not defined !'))
+ raise osv.except_osv(_('Error!'),
+ _('There is no Fiscal Position defined or Income category account defined for default properties of Product categories.'))
return {
'name': line.name,
'origin': line.order_id.name,
def button_cancel(self, cr, uid, ids, context=None):
for line in self.browse(cr, uid, ids, context=context):
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.'))
for move_line in line.move_ids:
if move_line.state != 'cancel':
raise osv.except_osv(
- _('Could not cancel sales order line!'),
+ _('Cannot cancel sales order line!'),
_('You must first cancel stock moves attached to this sales order line.'))
return self.write(cr, uid, ids, {'state': 'cancel'})
(qty, ean, qty_pack, type_ul.name)
warning_msgs += _("Picking Information ! : ") + warn_msg + "\n\n"
warning = {
- 'title': _('Configuration Error !'),
+ 'title': _('Configuration Error!'),
'message': warning_msgs
}
result['product_uom_qty'] = qty
context = context or {}
lang = lang or context.get('lang',False)
if not partner_id:
- raise osv.except_osv(_('No Customer Defined !'), _('You have to select a customer in the sales form !\nPlease set one customer before choosing a product.'))
+ raise osv.except_osv(_('No Customer Defined !'), _('Before choosing a product,\n select a customer in the sales form.'))
warning = {}
product_uom_obj = self.pool.get('product.uom')
partner_obj = self.pool.get('res.partner')
[('category_id', '=', product_obj.uom_id.category_id.id)],
'product_uos':
[('category_id', '=', uos_category_id)]}
-
elif uos and not uom: # only happens if uom is False
result['product_uom'] = product_obj.uom_id and product_obj.uom_id.id
result['product_uom_qty'] = qty_uos / product_obj.uos_coeff
'date': date_order,
})[pricelist]
if price is False:
- warn_msg = _("Couldn't find a pricelist line matching this product and quantity.\n"
+ warn_msg = _("Cannot find a pricelist line matching this product and quantity.\n"
"You have to change either the product, the quantity or the pricelist.")
warning_msgs += _("No valid pricelist line found ! :") + warn_msg +"\n\n"
result.update({'price_unit': price})
if warning_msgs:
warning = {
- 'title': _('Configuration Error !'),
+ 'title': _('Configuration Error!'),
'message' : warning_msgs
}
return {'value': result, 'domain': domain, 'warning': warning}
lang=False, update_tax=True, date_order=False, context=None):
context = context or {}
lang = lang or ('lang' in context and context['lang'])
- res = self.product_id_change(cursor, user, ids, pricelist, product,
+ if not uom:
+ return {'value': {'price_unit': 0.0, 'product_uom' : uom or False}}
+ return self.product_id_change(cursor, user, ids, pricelist, product,
qty=qty, uom=uom, qty_uos=qty_uos, uos=uos, name=name,
partner_id=partner_id, lang=lang, update_tax=update_tax,
date_order=date_order, context=context)
- if 'product_uom' in res['value']:
- del res['value']['product_uom']
- if not uom:
- res['value']['price_unit'] = 0.0
- return res
def unlink(self, cr, uid, ids, context=None):
if context is None:
"""Allows to delete sales order lines in draft,cancel states"""
for rec in self.browse(cr, uid, ids, context=context):
if rec.state not in ['draft', 'cancel']:
- raise osv.except_osv(_('Invalid action !'), _('Cannot delete a sales order line which is in state \'%s\'!') %(rec.state,))
+ raise osv.except_osv(_('Invalid Action!'), _('Cannot delete a sales order line which is in state \'%s\'.') %(rec.state,))
return super(sale_order_line, self).unlink(cr, uid, ids, context=context)
sale_order_line()
class mail_message(osv.osv):
_inherit = 'mail.message'
-
+
def _postprocess_sent_message(self, cr, uid, message, context=None):
if message.model == 'sale.order':
wf_service = netsvc.LocalService("workflow")
- wf_service.trg_validate(uid, 'sale.order', message.res_id, 'quotation_sent', cr)
+ wf_service.trg_validate(uid, 'sale.order', message.res_id, 'quotation_sent', cr)
return super(mail_message, self)._postprocess_sent_message(cr, uid, message=message, context=context)
mail_message()