[IMP] sale: put stat button with invoices on sale order.
invoice_exists field has been removed, because invoice_count can be used when the old field was used. invoiced_rate field has been removed, because it was never used except in a test. Also added a stat button with deliveries on sale order.
This commit is contained in:
committed by
Thibault Delavallée
parent
6de2fa858a
commit
d6fe36f1f7
@@ -416,15 +416,21 @@ class purchase_order(osv.osv):
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
act_obj = self.pool.get('ir.actions.act_window')
|
||||
|
||||
result = mod_obj.get_object_reference(cr, uid, 'account', 'action_invoice_tree2')
|
||||
id = result and result[1] or False
|
||||
result = act_obj.read(cr, uid, [id], context=context)[0]
|
||||
action_id = mod_obj.xmlid_to_res_id(cr, uid, 'account.action_invoice_tree2')
|
||||
result = act_obj.read(cr, uid, action_id, context=context)
|
||||
inv_ids = []
|
||||
for po in self.browse(cr, uid, ids, context=context):
|
||||
inv_ids+= [invoice.id for invoice in po.invoice_ids]
|
||||
inv_ids += [invoice.id for invoice in po.invoice_ids]
|
||||
if not inv_ids:
|
||||
raise UserError(_('Please create Invoices.'))
|
||||
result['domain'] = [('id', 'in', inv_ids)]
|
||||
|
||||
if len(inv_ids) > 1:
|
||||
result['domain'] = [('id', 'in', inv_ids)]
|
||||
else:
|
||||
res = mod_obj.xmlid_to_res_id(cr, uid, 'account.invoice_supplier_form')
|
||||
result['views'] = [(res, 'form')]
|
||||
result['res_id'] = inv_ids and inv_ids[0] or False
|
||||
return result
|
||||
|
||||
def view_invoice(self, cr, uid, ids, context=None):
|
||||
'''
|
||||
|
||||
+15
-48
@@ -68,47 +68,7 @@ class sale_order(osv.osv):
|
||||
res[order.id]['amount_total'] = res[order.id]['amount_untaxed'] + res[order.id]['amount_tax']
|
||||
return res
|
||||
|
||||
|
||||
def _invoiced_rate(self, cursor, user, ids, name, arg, context=None):
|
||||
res = {}
|
||||
for sale in self.browse(cursor, user, ids, context=context):
|
||||
if sale.invoiced:
|
||||
res[sale.id] = 100.0
|
||||
continue
|
||||
tot = 0.0
|
||||
for invoice in sale.invoice_ids:
|
||||
if invoice.state not in ('draft', 'cancel'):
|
||||
tot += invoice.amount_untaxed
|
||||
if tot:
|
||||
res[sale.id] = min(100.0, tot * 100.0 / (sale.amount_untaxed or 1.00))
|
||||
else:
|
||||
res[sale.id] = 0.0
|
||||
return res
|
||||
|
||||
def _invoice_exists(self, cursor, user, ids, name, arg, context=None):
|
||||
res = {}
|
||||
for sale in self.browse(cursor, user, ids, context=context):
|
||||
res[sale.id] = False
|
||||
if sale.invoice_ids:
|
||||
res[sale.id] = True
|
||||
return res
|
||||
|
||||
def _invoiced(self, cursor, user, ids, name, arg, context=None):
|
||||
res = {}
|
||||
for sale in self.browse(cursor, user, ids, context=context):
|
||||
res[sale.id] = True
|
||||
invoice_existence = False
|
||||
for invoice in sale.invoice_ids:
|
||||
if invoice.state!='cancel':
|
||||
invoice_existence = True
|
||||
if invoice.state != 'paid':
|
||||
res[sale.id] = False
|
||||
break
|
||||
if not invoice_existence or sale.state == 'manual':
|
||||
res[sale.id] = False
|
||||
return res
|
||||
|
||||
def _invoiced_search(self, cursor, user, obj, name, args, context=None):
|
||||
def _search_invoiced(self, cursor, user, obj, name, args, context=None):
|
||||
if not len(args):
|
||||
return []
|
||||
clause = ''
|
||||
@@ -169,6 +129,17 @@ class sale_order(osv.osv):
|
||||
return int(team_ids[0][0])
|
||||
return None
|
||||
|
||||
def _get_invoiced(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = {}
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
res[order.id] = {
|
||||
'invoice_count': len(order.invoice_ids),
|
||||
'invoiced': False,
|
||||
}
|
||||
if order.state != 'manual' and any(invoice.state == 'paid' for invoice in order.invoice_ids):
|
||||
res[order.id]['invoiced'] = True
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Order Reference', required=True, copy=False,
|
||||
readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, select=True),
|
||||
@@ -206,13 +177,9 @@ class sale_order(osv.osv):
|
||||
|
||||
'order_line': fields.one2many('sale.order.line', 'order_id', 'Order Lines', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, copy=True),
|
||||
'invoice_ids': fields.many2many('account.invoice', 'sale_order_invoice_rel', 'order_id', 'invoice_id', 'Invoices', readonly=True, copy=False, help="This is the list of invoices that have been generated for this sales order. The same sales order may have been invoiced in several times (by line for example)."),
|
||||
'invoiced_rate': fields.function(_invoiced_rate, string='Invoiced Ratio', type='float'),
|
||||
'invoiced': fields.function(_invoiced, string='Paid',
|
||||
fnct_search=_invoiced_search, type='boolean', help="It indicates that an invoice has been paid."),
|
||||
'invoice_exists': fields.function(_invoice_exists, string='Invoiced',
|
||||
fnct_search=_invoiced_search, type='boolean', help="It indicates that sales order has at least one invoice."),
|
||||
'invoice_count': fields.function(_get_invoiced, type='integer', string='Invoices', multi="counts"),
|
||||
'invoiced': fields.function(_get_invoiced, fnct_search=_search_invoiced, type='boolean', string='Paid', multi="counts"),
|
||||
'note': fields.text('Terms and conditions'),
|
||||
|
||||
'amount_untaxed': fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string='Untaxed Amount',
|
||||
store={
|
||||
'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
|
||||
@@ -682,7 +649,7 @@ class sale_order(osv.osv):
|
||||
|
||||
def action_ignore_delivery_exception(self, cr, uid, ids, context=None):
|
||||
for sale_order in self.browse(cr, uid, ids, context=context):
|
||||
self.write(cr, uid, ids, {'state': 'progress' if sale_order.invoice_exists else 'manual'}, context=context)
|
||||
self.write(cr, uid, ids, {'state': 'progress' if sale_order.invoice_count else 'manual'}, context=context)
|
||||
return True
|
||||
|
||||
def action_ship_create(self, cr, uid, ids, context=None):
|
||||
|
||||
@@ -99,8 +99,6 @@
|
||||
<button name="print_quotation" string="Print" type="object" states="draft" class="oe_highlight" groups="base.group_user"/>
|
||||
<button name="print_quotation" string="Print" type="object" states="sent,progress,manual" groups="base.group_user"/>
|
||||
<button name="action_button_confirm" states="draft" string="Confirm Sale" type="object" groups="base.group_user"/>
|
||||
<button name="action_view_invoice" string="View Invoice" type="object" class="oe_highlight"
|
||||
attrs="{'invisible': [('invoice_exists', '=', False)]}" groups="base.group_user"/>
|
||||
<button name="%(action_view_sale_advance_payment_inv)d" string="Create Invoice"
|
||||
type="action" states="manual" class="oe_highlight" groups="base.group_user"/>
|
||||
<button name="copy_quotation" states="cancel" string="New Copy of Quotation" type="object"/>
|
||||
@@ -110,11 +108,22 @@
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,sent,progress,done" statusbar_colors='{"invoice_except":"red","waiting_date":"blue"}'/>
|
||||
</header>
|
||||
<sheet>
|
||||
<h1>
|
||||
<label string="Quotation " attrs="{'invisible': [('state','not in',('draft','sent'))]}"/>
|
||||
<label string="Sales Order " attrs="{'invisible': [('state','in',('draft','sent'))]}"/>
|
||||
<field name="name" class="oe_inline" readonly="1"/>
|
||||
</h1>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<label string="Quotation " attrs="{'invisible': [('state', 'not in', ('draft', 'sent'))]}"/>
|
||||
<label string="Sales Order " attrs="{'invisible': [('state', 'in', ('draft', 'sent'))]}"/>
|
||||
<field name="name" class="oe_inline" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="oe_right oe_button_box" name="buttons">
|
||||
<button name="action_view_invoice"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-pencil-square-o"
|
||||
attrs="{'invisible': [('invoice_count', '=', 0)]}" groups="base.group_user">
|
||||
<field name="invoice_count" widget="statinfo" string="Invoices"/>
|
||||
</button>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id, context)" domain="[('customer','=',True)]" context="{'search_default_customer':1, 'show_address': 1}" options='{"always_reload": True}'/>
|
||||
@@ -221,7 +230,6 @@
|
||||
<field name="user_id" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'account.group_account_invoice', 'base.group_sale_salesman_all_leads']}"/>
|
||||
<field name="team_id" options="{'no_create': True}" groups="base.group_multi_salesteams"/>
|
||||
<field name="client_order_ref"/>
|
||||
<field name="invoice_exists" invisible="1"/>
|
||||
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group name="sale_pay" string="Invoicing">
|
||||
|
||||
@@ -64,6 +64,6 @@
|
||||
!python {model: sale.order}: |
|
||||
sale_order = self.browse(cr, uid, ref("sale_order_2"))
|
||||
assert sale_order.invoice_ids, "Invoice should be created."
|
||||
assert sale_order.invoice_exists, "Order is not invoiced."
|
||||
assert sale_order.invoice_count, "Order is not invoiced."
|
||||
assert sale_order.invoiced, "Order is not paid."
|
||||
assert sale_order.state == 'done', 'Order should be Done.'
|
||||
|
||||
@@ -89,6 +89,12 @@ class sale_order(osv.osv):
|
||||
invoice_vals['incoterms_id'] = order.incoterm.id or False
|
||||
return invoice_vals
|
||||
|
||||
def _get_delivery_count(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = {}
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
res[order.id] = len(picking for picking in order.picking_ids if picking.picking_type_id.code == 'outgoing')
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'incoterm': fields.many2one('stock.incoterms', 'Incoterms', help="International Commercial Terms are a series of predefined commercial terms used in international transactions."),
|
||||
'picking_policy': fields.selection([('direct', 'Deliver each product when available'), ('one', 'Deliver all products at once')],
|
||||
@@ -105,6 +111,7 @@ class sale_order(osv.osv):
|
||||
}),
|
||||
'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', required=True, readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}),
|
||||
'picking_ids': fields.function(_get_picking_ids, method=True, type='one2many', relation='stock.picking', string='Picking associated to this sale'),
|
||||
'delivery_count': fields.function(_get_delivery_count, type='integer', string='Delivery Orders'),
|
||||
}
|
||||
_defaults = {
|
||||
'warehouse_id': _get_default_warehouse,
|
||||
@@ -136,8 +143,8 @@ class sale_order(osv.osv):
|
||||
#compute the number of delivery orders to display
|
||||
pick_ids = []
|
||||
for so in self.browse(cr, uid, ids, context=context):
|
||||
pick_ids += [picking.id for picking in so.picking_ids]
|
||||
|
||||
pick_ids += [picking.id for picking in so.picking_ids if picking.picking_type_id.code == 'outgoing']
|
||||
|
||||
#choose the view_mode accordingly
|
||||
if len(pick_ids) > 1:
|
||||
result['domain'] = "[('id','in',[" + ','.join(map(str, pick_ids)) + "])]"
|
||||
|
||||
@@ -12,11 +12,16 @@
|
||||
<button name="ship_recreate" states="shipping_except" string="Recreate Delivery Order"/>
|
||||
<button name="ship_corrected" states="shipping_except" string="Ignore Exception"/>
|
||||
</xpath>
|
||||
<xpath expr="//button[@name='action_view_invoice']" position="after">
|
||||
<xpath expr="//button[@name='action_view_invoice']" position="before">
|
||||
<field name="picking_ids" invisible="1"/>
|
||||
<button name="action_view_delivery" string="View Delivery Order" type="object" class="oe_highlight"
|
||||
attrs="{'invisible': ['|',('picking_ids','=',False),('picking_ids','=',[])]}" groups="base.group_user"/>
|
||||
</xpath>
|
||||
<button type="object"
|
||||
name="action_view_delivery"
|
||||
class="oe_stat_button"
|
||||
icon="fa-truck"
|
||||
attrs="{'invisible': [('delivery_count', '=', 0)]}" groups="base.group_user">
|
||||
<field name="delivery_count" widget="statinfo" string="Transfers" help="Delivery Orders"/>
|
||||
</button>
|
||||
</xpath>
|
||||
<xpath expr="//button[@name='action_cancel']" position="after">
|
||||
<button name="ship_cancel" states="shipping_except" string="Cancel Order"/>
|
||||
</xpath>
|
||||
@@ -56,7 +61,6 @@
|
||||
</xpath>
|
||||
<xpath expr="//group[@name='technical']" position="inside">
|
||||
<field name="shipped" groups="base.group_no_one"/>
|
||||
<field name="invoice_exists" invisible="1" groups="base.group_no_one"/>
|
||||
</xpath>
|
||||
<xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/group/group/field[@name='tax_id']" position="after">
|
||||
<label for="delay"/>
|
||||
|
||||
@@ -218,5 +218,4 @@
|
||||
!python {model: sale.order}: |
|
||||
order = self.browse(cr, uid, ref("sale_order_service"))
|
||||
assert order.invoiced == True, "Sale order is not invoiced."
|
||||
assert order.invoiced_rate == 100, "Invoiced progress is not 100%."
|
||||
assert order.state == 'done', 'Order should be in closed.'
|
||||
|
||||
Reference in New Issue
Block a user