[IMP] sale: adaptation due to the new Sale module

Invoicing is now completely handled from the SO.
cf. documentation

Reason: complete rewrite of the Sale module.

Responsible: fp, dbo, nim
This commit is contained in:
Nicolas Martinelli
2015-08-27 19:19:36 +02:00
parent 67ec9694d9
commit 94716a3f14
33 changed files with 1524 additions and 2502 deletions
+1
View File
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import sale
import sale_analytic
import sales_team
import res_partner
import wizard
+3 -13
View File
@@ -42,11 +42,8 @@ The Dashboard for the Sales Manager will include
'depends': ['sales_team','account', 'procurement', 'report'],
'data': [
'wizard/sale_make_invoice_advance.xml',
'wizard/sale_line_invoice.xml',
'wizard/sale_make_invoice.xml',
'security/sale_security.xml',
'security/ir.model.access.csv',
'sale_workflow.xml',
'sale_sequence.xml',
'sale_report.xml',
'sale_data.xml',
@@ -61,16 +58,9 @@ The Dashboard for the Sales Manager will include
'sales_team_dashboard.xml',
'sale_tip_data.xml',
],
'demo': ['sale_demo.xml'],
'test': [
'../account/test/account_minimal_test.xml',
'test/create_sale_users.yml',
'test/sale_order_demo.yml',
'test/manual_order_policy.yml',
'test/cancel_order.yml',
'test/delete_order.yml',
'test/canceled_lines_order.yml',
],
'demo': ['sale_demo.xml',
'sale_product_demo.xml',
],
'css': ['static/src/css/sale.css'],
'installable': True,
'auto_install': False,
+7 -11
View File
@@ -1,21 +1,17 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.osv import fields,osv
class account_invoice_report(osv.osv):
from openerp import api, fields, models, _
class AccountInvoiceReport(models.Model):
_inherit = 'account.invoice.report'
_columns = {
'team_id': fields.many2one('crm.team', 'Sales Team', oldname='section_id'),
}
_depends = {
'account.invoice': ['team_id'],
}
team_id = fields.Many2one('crm.team', string='Sales Team')
def _select(self):
return super(account_invoice_report, self)._select() + ", sub.team_id as team_id"
return super(AccountInvoiceReport, self)._select() + ", sub.team_id as team_id"
def _sub_select(self):
return super(account_invoice_report, self)._sub_select() + ", ai.team_id as team_id"
return super(AccountInvoiceReport, self)._sub_select() + ", ai.team_id as team_id"
def _group_by(self):
return super(account_invoice_report, self)._group_by() + ", ai.team_id"
return super(AccountInvoiceReport, self)._group_by() + ", ai.team_id"
+20 -22
View File
@@ -11,33 +11,32 @@ class sale_report(osv.osv):
_rec_name = 'date'
_columns = {
'date': fields.datetime('Date Order', readonly=True), # TDE FIXME master: rename into date_order
'date_confirm': fields.date('Date Confirm', readonly=True),
'date': fields.datetime('Date Order', readonly=True),
'product_id': fields.many2one('product.product', 'Product', readonly=True),
'product_uom': fields.many2one('product.uom', 'Unit of Measure', readonly=True),
'product_uom_qty': fields.float('# of Qty', readonly=True),
'qty_delivered': fields.float('Qty Delivered', readonly=True),
'qty_to_invoice': fields.float('Qty To Invoice', readonly=True),
'qty_invoiced': fields.float('Qty Invoiced', readonly=True),
'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True),
'user_id': fields.many2one('res.users', 'Salesperson', readonly=True),
'price_total': fields.float('Total Price', readonly=True),
'delay': fields.float('Commitment Delay', digits=(16,2), readonly=True),
'product_tmpl_id': fields.many2one('product.template', 'Product Template', readonly=True),
'categ_id': fields.many2one('product.category','Product Category', readonly=True),
'nbr': fields.integer('# of Lines', readonly=True), # TDE FIXME master: rename into nbr_lines
'state': fields.selection([
('cancel', 'Cancelled'),
('draft', 'Draft'),
('confirmed', 'Confirmed'),
('exception', 'Exception'),
('done', 'Done')], 'Order Status', readonly=True),
'nbr': fields.integer('# of Lines', readonly=True),
'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', readonly=True),
'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
'invoiced': fields.boolean('Paid', readonly=True),
'nbr_paid': fields.integer('# of Paid Lines', readonly=True),
'team_id': fields.many2one('crm.team', 'Sales Team', readonly=True, oldname='section_id'),
'country_id': fields.many2one('res.country', 'Partner Country', readonly=True),
'commercial_partner_id': fields.many2one('res.partner', 'Commercial Entity', readonly=True),
'state': fields.selection([
('draft', 'Draft Quotation'),
('sent', 'Quotation Sent'),
('sale', 'Sales Order'),
('done', 'Sales Done'),
('cancel', 'Cancelled'),
], string='Status', readonly=True),
}
_order = 'date desc'
@@ -56,22 +55,23 @@ class sale_report(osv.osv):
l.product_id as product_id,
t.uom_id as product_uom,
sum(l.product_uom_qty / u.factor * u2.factor) as product_uom_qty,
sum(l.product_uom_qty * cr.rate * l.price_unit * (100.0-l.discount) / 100.0) as price_total,
sum(l.qty_delivered / u.factor * u2.factor) as qty_delivered,
sum(l.qty_invoiced / u.factor * u2.factor) as qty_invoiced,
sum(l.qty_to_invoice / u.factor * u2.factor) as qty_to_invoice,
sum(l.price_total * cr.rate) as price_total,
sum(l.price_subtotal * cr.rate) as price_subtotal,
count(*) as nbr,
s.date_order as date,
s.date_confirm as date_confirm,
s.state as state,
s.partner_id as partner_id,
s.user_id as user_id,
s.company_id as company_id,
extract(epoch from avg(date_trunc('day',s.date_confirm)-date_trunc('day',s.create_date)))/(24*60*60)::decimal(16,2) as delay,
l.state,
extract(epoch from avg(date_trunc('day',s.date_order)-date_trunc('day',s.create_date)))/(24*60*60)::decimal(16,2) as delay,
t.categ_id as categ_id,
s.pricelist_id as pricelist_id,
s.project_id as analytic_account_id,
s.team_id as team_id,
p.product_tmpl_id,
l.invoiced::integer as nbr_paid,
l.invoiced,
partner.country_id as country_id,
partner.commercial_partner_id as commercial_partner_id
"""
@@ -100,16 +100,14 @@ class sale_report(osv.osv):
t.uom_id,
t.categ_id,
s.date_order,
s.date_confirm,
s.partner_id,
s.user_id,
s.state,
s.company_id,
l.state,
s.pricelist_id,
s.project_id,
s.team_id,
p.product_tmpl_id,
l.invoiced,
partner.country_id,
partner.commercial_partner_id
"""
+1 -2
View File
@@ -58,10 +58,9 @@
<field name="arch" type="xml">
<search string="Sales Analysis">
<field name="date"/>
<field name="date_confirm"/>
<filter string="This Year" name="year" invisible="1" domain="[('date','&lt;=', time.strftime('%%Y-12-31')),('date','&gt;=',time.strftime('%%Y-01-01'))]"/>
<filter name="Quotations" domain="[('state','in',('draft'))]"/>
<filter name="Sales" string="Sales" domain="[('state','not in',('draft', 'cancel'))]"/>
<filter name="Sales" string="Sales" domain="[('state','not in',('draft', 'cancel', 'sent'))]"/>
<separator/>
<field name="partner_id"/>
<field name="product_id"/>
+11 -12
View File
@@ -4,7 +4,6 @@
import logging
from openerp.osv import fields, osv
from openerp.tools.translate import _
_logger = logging.getLogger(__name__)
@@ -19,15 +18,6 @@ class sale_configuration(osv.TransientModel):
], "Product Variants",
help='Work with product variant allows you to define some variant of the same products, an ease the product management in the ecommerce for example',
implied_group='product.group_product_variant'),
'module_sale_contract': fields.selection([
(0, 'Sell based on sales order only'),
(1, 'Activate contract management to track costs and revenues')
], "Contracts",
help='Allows to define your customer contracts conditions: invoicing '
'method (fixed price, on timesheet, advance invoice), the exact pricing '
'(650€/day for a developer), the duration (one year support contract).\n'
'You will be able to follow the progress of the contract and invoice automatically.\n'
'-It installs the sale_contract module.'),
'group_sale_pricelist':fields.selection([
(0, 'Set a fixed sale price on each product'),
(1, 'Use pricelists to adapt your price per customers or products')
@@ -67,10 +57,19 @@ class sale_configuration(osv.TransientModel):
'group_sale_delivery_address': fields.selection([
(0, "Invoicing and shipping addresses are always the same (Example: services companies)"),
(1, 'Have 3 fields on sales orders: customer, invoice address, delivery address')
], "Customer Addresses",
implied_group='sale.group_delivery_invoice_address'),
], "Customer Addresses", implied_group='sale.group_delivery_invoice_address'),
'default_invoice_policy': fields.selection([
('order', 'Invoice ordered quantities'),
('delivery', 'Invoice delivered quantities'),
('cost', 'Invoice based on costs (time and material, expenses)')
], 'Default Invoicing', default_model='product.template')
}
_defaults = {
'default_invoice_policy': 'order',
}
def set_sale_defaults(self, cr, uid, ids, context=None):
return {}
+1 -3
View File
@@ -11,6 +11,7 @@
<field name="group_product_variant" widget="radio"/>
<field name="module_website_sale_digital" widget="radio"/>
<field name="group_uom" widget="radio"/>
<field name="default_invoice_policy" widget="radio"/>
</group>
<group string="Quotations &amp; Sales" id="sale">
<field name="group_sale_pricelist" widget="radio"/>
@@ -20,9 +21,6 @@
<field name="module_website_quote" widget="radio"/>
<field name="module_sale_margin" widget="radio"/>
</group>
<group string="Contracts" id="contract">
<field name="module_sale_contract" widget="radio"/>
</group>
</div>
</field>
</record>
+1 -1
View File
@@ -6,7 +6,7 @@
<field name="res_model">sale.order</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,graph</field>
<field name="context">{'search_default_partner_id': active_id}</field>
<field name="context">{'search_default_partner_id': active_id, 'show_sale': True}</field>
<field name="groups_id" eval="[(4, ref('base.group_sale_salesman'))]"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
+614 -1098
View File
File diff suppressed because it is too large Load Diff
+108
View File
@@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp import api, fields, models
class SaleOrderLine(models.Model):
_inherit = "sale.order.line"
@api.multi
def _compute_analytic(self, domain=None):
lines = {}
if not domain:
domain = [('so_line', 'in', self.ids), ('amount', '<', 0.0)]
data = self.env['account.analytic.line'].read_group(
domain,
['so_line', 'unit_amount', 'product_uom_id'], ['product_uom_id', 'so_line'], lazy=False
)
for d in data:
if not d['product_uom_id']:
continue
line = self.browse(d['so_line'][0])
lines.setdefault(line, 0.0)
uom = self.env['product.uom'].browse(d['product_uom_id'][0])
qty = self.env['product.uom']._compute_qty_obj(uom, d['unit_amount'], line.product_uom)
lines[line] += qty
for line, qty in lines.items():
line.qty_delivered = qty
return True
class AccountAnalyticLine(models.Model):
_inherit = "account.analytic.line"
so_line = fields.Many2one('sale.order.line', string='Sale Order Line')
def _get_invoice_price(self, order):
return abs(self.amount / self.unit_amount)
def _get_sale_order_line_vals(self):
order = self.env['sale.order'].search([('project_id', '=', self.account_id.id), ('state', '=', 'sale')], limit=1)
last_so_line = self.env['sale.order.line'].search([('order_id', '=', order.id)], order='sequence desc', limit=1)
last_sequence = last_so_line.sequence + 1 if last_so_line else 100
fpos = order.fiscal_position_id or order.partner_id.property_account_position_id
taxes = fpos.map_tax(self.product_id.taxes_id)
price = self._get_invoice_price(order)
return {
'order_id': order.id,
'name': self.name,
'sequence': last_sequence,
'price_unit': price,
'tax_id': [x.id for x in taxes],
'discount': 0.0,
'product_id': self.product_id.id,
'product_uom': self.product_uom_id.id,
'product_uom_qty': 0.0,
'qty_delivered': self.unit_amount,
}
def _get_sale_order_line(self, vals=None):
result = dict(vals or {})
sol = result.get('so_line', False) or self.so_line
if not sol and self.account_id and self.product_id and self.product_id.invoice_policy in ('cost', 'order'):
sol = self.env['sale.order.line'].search([
('order_id.project_id', '=', self.account_id.id),
('state', '=', 'sale'),
('product_id', '=', self.product_id.id)],
limit=1)
result.update({'so_line': sol.id})
if not sol and self.account_id and self.product_id and self.product_id.invoice_policy == 'cost':
order_line_vals = self._get_sale_order_line_vals()
sol = self.env['sale.order.line'].create(order_line_vals)
sol._compute_tax_id()
result.update({'so_line': sol.id})
return result
@api.multi
def write(self, values):
if self._context.get('create', False):
return super(AccountAnalyticLine, self).write(values)
todo = self.mapped('so_line')
result = super(AccountAnalyticLine, self).write(values)
if 'so_line' in values:
todo |= self.mapped('so_line')
for line in self:
res = self._get_sale_order_line(vals=values)
super(AccountAnalyticLine, line).write(res)
if 'so_line' in res:
todo |= line.mapped('so_line')
todo._compute_analytic()
return result
@api.model
def create(self, values):
line = super(AccountAnalyticLine, self).create(values)
res = line._get_sale_order_line(vals=values)
line.with_context(create=True).write(res)
line.mapped('so_line')._compute_analytic()
return line
+4 -29
View File
@@ -25,7 +25,6 @@
<field name="name">Laptop E5023</field>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">3</field>
<field name="product_uos_qty">3</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">2950.00</field>
</record>
@@ -35,7 +34,6 @@
<field name="name">Pen drive, 16GB</field>
<field name="product_id" ref="product.product_product_30"/>
<field name="product_uom_qty">5</field>
<field name="product_uos_qty">5</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">145.00</field>
</record>
@@ -45,7 +43,6 @@
<field name="name">Headset USB</field>
<field name="product_id" ref="product.product_product_33"/>
<field name="product_uom_qty">2</field>
<field name="product_uos_qty">2</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">65.00</field>
</record>
@@ -56,7 +53,6 @@
<field name="partner_shipping_id" ref="base.res_partner_address_13"/>
<field name="user_id" ref="base.user_root"/>
<field name="pricelist_id" ref="product.list0"/>
<field name="order_policy">manual</field>
<field name="team_id" ref="sales_team.team_sales_department"/>
<field name="date_order" eval="(DateTime.today() - relativedelta(months=1)).strftime('%Y-%m-%d %H:%M')"/>
</record>
@@ -66,7 +62,6 @@
<field name="name">Service on demand</field>
<field name="product_id" ref="product.product_product_1"/>
<field name="product_uom_qty">24</field>
<field name="product_uos_qty">24</field>
<field name="product_uom" ref="product.product_uom_hour"/>
<field name="price_unit">75.00</field>
</record>
@@ -76,7 +71,6 @@
<field name="name">On Site Assistance</field>
<field name="product_id" ref="product.product_product_2"/>
<field name="product_uom_qty">30</field>
<field name="product_uos_qty">30</field>
<field name="product_uom" ref="product.product_uom_hour"/>
<field name="price_unit">38.25</field>
</record>
@@ -87,7 +81,6 @@
<field name="partner_shipping_id" ref="base.res_partner_4"/>
<field name="user_id" ref="base.user_root"/>
<field name="pricelist_id" ref="product.list0"/>
<field name="order_policy">manual</field>
<field name="team_id" ref="sales_team.team_sales_department"/>
</record>
@@ -96,7 +89,6 @@
<field name="name">On Site Monitoring</field>
<field name="product_id" ref="product.product_product_1"/>
<field name="product_uom_qty">10</field>
<field name="product_uos_qty">10</field>
<field name="product_uom" ref="product.product_uom_hour"/>
<field name="price_unit">30.75</field>
</record>
@@ -106,7 +98,6 @@
<field name="name">Toner Cartridge</field>
<field name="product_id" ref="product.product_product_39"/>
<field name="product_uom_qty">1</field>
<field name="product_uos_qty">1</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">70.00</field>
</record>
@@ -125,7 +116,6 @@
<field name="name">Service on demand</field>
<field name="product_id" ref="product.product_product_1"/>
<field name="product_uom_qty">16</field>
<field name="product_uos_qty">16</field>
<field name="product_uom" ref="product.product_uom_hour"/>
<field name="price_unit">75.00</field>
</record>
@@ -135,7 +125,6 @@
<field name="name">Webcam</field>
<field name="product_id" ref="product.product_product_34"/>
<field name="product_uom_qty">10</field>
<field name="product_uos_qty">10</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">45.00</field>
</record>
@@ -145,7 +134,6 @@
<field name="name">Multimedia Speakers</field>
<field name="product_id" ref="product.product_product_31"/>
<field name="product_uom_qty">3</field>
<field name="product_uos_qty">3</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">150.00</field>
</record>
@@ -155,7 +143,6 @@
<field name="name">Switch, 24 ports</field>
<field name="product_id" ref="product.product_product_47"/>
<field name="product_uom_qty">2</field>
<field name="product_uos_qty">2</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">70.00</field>
</record>
@@ -175,7 +162,6 @@
<field name="name">External Hard disk</field>
<field name="product_id" ref="product.product_product_28"/>
<field name="product_uom_qty">1</field>
<field name="product_uos_qty">1</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">405.00</field>
</record>
@@ -185,7 +171,6 @@
<field name="name">Blank DVD-RW</field>
<field name="product_id" ref="product.product_product_36"/>
<field name="product_uom_qty">3</field>
<field name="product_uos_qty">3</field>
<field name="product_uom" ref="product.product_uom_dozen"/>
<field name="price_unit">24.00</field>
</record>
@@ -195,7 +180,6 @@
<field name="name">Printer, All-in-one</field>
<field name="product_id" ref="product.product_product_37"/>
<field name="product_uom_qty">1</field>
<field name="product_uos_qty">1</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">4410.00</field>
</record>
@@ -214,7 +198,6 @@
<field name="name">PC Assamble + 2GB RAM</field>
<field name="product_id" ref="product.product_product_4"/>
<field name="product_uom_qty">1</field>
<field name="product_uos_qty">1</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">750.00</field>
</record>
@@ -225,9 +208,7 @@
<field name="partner_shipping_id" ref="base.res_partner_address_11"/>
<field name="user_id" ref="base.user_root"/>
<field name="pricelist_id" ref="product.list0"/>
<field name="order_policy">manual</field>
<field name="team_id" ref="sales_team.team_sales_department"/>
<field name="date_confirm" eval="(DateTime.today() - relativedelta(months=1)).strftime('%Y-%m-%d %H:%M')"/>
</record>
<record id="sale_order_line_16" model="sale.order.line">
@@ -235,7 +216,6 @@
<field name="name">Laptop E5023</field>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">5</field>
<field name="product_uos_qty">5</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">2950.00</field>
</record>
@@ -245,7 +225,6 @@
<field name="name">GrapWorks Software</field>
<field name="product_id" ref="product.product_product_44"/>
<field name="product_uom_qty">1</field>
<field name="product_uos_qty">1</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">173.00</field>
</record>
@@ -255,7 +234,6 @@
<field name="name">Datacard</field>
<field name="product_id" ref="product.product_product_46"/>
<field name="product_uom_qty">1</field>
<field name="product_uos_qty">1</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">40.00</field>
</record>
@@ -265,7 +243,6 @@
<field name="name">USB Adapter</field>
<field name="product_id" ref="product.product_product_48"/>
<field name="product_uom_qty">1</field>
<field name="product_uos_qty">1</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">18.00</field>
</record>
@@ -277,7 +254,6 @@
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
<field name="user_id" ref="base.user_demo"/>
<field name="pricelist_id" ref="product.list0"/>
<field name="order_policy">manual</field>
<field name="team_id" ref="sales_team.crm_team_1"/>
</record>
@@ -286,7 +262,6 @@
<field name="name">Laptop Customized</field>
<field name="product_id" ref="product.product_product_27"/>
<field name="product_uom_qty">2</field>
<field name="product_uos_qty">2</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">3645.00</field>
</record>
@@ -296,7 +271,6 @@
<field name="name">Mouse, Wireless</field>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">2</field>
<field name="product_uos_qty">2</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">12.50</field>
</record>
@@ -340,13 +314,14 @@ Thanks!</field>
<!-- Demo Data for Product -->
<record id="advance_product_0" model="product.product">
<field name="name">Advance</field>
<field name="name">Deposit</field>
<field name="categ_id" ref="product.product_category_1"/>
<field name="type">service</field>
<field name="list_price">150.0</field>
<field name="invoice_policy">order</field>
<field name="standard_price">100.0</field>
<field name="uom_id" ref="product.product_uom_day"/>
<field name="uom_po_id" ref="product.product_uom_day"/>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="company_id" eval="[]"/>
<field name="image" type="base64" file="sale/static/img/advance_product_0-image.jpg"/>
</record>
+273
View File
@@ -0,0 +1,273 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="product.product_product_59" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_58" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_57" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_56" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_55" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_54" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_53" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_52" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_51" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_50" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_49" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_48" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_47" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_46" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_45" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_44" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_43" model="product.product">
<field name="invoice_policy">order</field>
</record>
<record id="product.product_product_42" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_41" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_40" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_39" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_38" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_37" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_36" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_35" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_34" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_33" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_32" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_31" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_30" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_29" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_28" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_27" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_26" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_25" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_24" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_23" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_22" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_21" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_20" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_19" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_18" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_17" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_16" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_15" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_14" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_13" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_12" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_11b" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_11" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_10" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_9" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_8" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_7" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_6" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_5" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_5b" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_4d" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_4d" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_4c" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_4b" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_4" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_3" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_2" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_1" model="product.product">
<field name="invoice_policy">delivery</field>
</record>
<record id="product.product_product_1b" model="product.product">
<field name="invoice_policy">cost</field>
</record>
<record id="product.product_product_0" model="product.product">
<field name="invoice_policy">order</field>
</record>
</data>
</openerp>
-2
View File
@@ -17,7 +17,6 @@
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">450</field>
<field name="product_uom_qty">2</field>
<field name="product_uos_qty">2</field>
</record>
<record id="test_order_1_line_3" model="sale.order.line">
<field name="order_id" ref="test_order_1"/>
@@ -26,7 +25,6 @@
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">90</field>
<field name="product_uom_qty">3</field>
<field name="product_uos_qty">3</field>
</record>
<assert id="test_order_1" model="sale.order" severity="error" string="The amount of the sales order is correctly computed">
+150 -221
View File
@@ -44,7 +44,7 @@
<field name="model">sale.order</field>
<field name="arch" type="xml">
<pivot string="Sales Orders">
<field name="partner_id" type="row"/>
<field name="date_order" type="row"/>
<field name="amount_total" type="measure"/>
</pivot>
</field>
@@ -59,7 +59,7 @@
<field name="name"/>
<field name="partner_id"/>
<field name="amount_total"/>
<field name="date_confirm"/>
<field name="date_order"/>
<field name="state"/>
<templates>
<t t-name="kanban-box">
@@ -74,10 +74,10 @@
</div>
<div class="row">
<div class="col-xs-6 text-muted">
<span><t t-esc="record.name.value"/> <t t-esc="record.date_confirm.value"/></span>
<span><t t-esc="record.name.value"/> <t t-esc="record.date_order.value"/></span>
</div>
<div class="col-xs-6">
<span t-attf-class="pull-right text-right label #{['draft', 'cancel'].indexOf(record.state.raw_value) > -1 ? 'label-default' : ['except_picking', 'invoice_except'].indexOf(record.state.raw_value) > -1 ? 'label-danger' : ['waiting_date', 'manual'].indexOf(record.state.raw_value) > -1 ? 'label-warning' : ['done'].indexOf(record.state.raw_value) > -1 ? 'label-success' : 'label-primary'}"><t t-esc="record.state.value"/></span>
<span t-attf-class="pull-right text-right label #{['draft', 'cancel'].indexOf(record.state.raw_value) > -1 ? 'label-default' : ['done'].indexOf(record.state.raw_value) > -1 ? 'label-success' : 'label-primary'}"><t t-esc="record.state.value"/></span>
</div>
</div>
</div>
@@ -92,14 +92,15 @@
<field name="model">sale.order</field>
<field name="priority">2</field>
<field name="arch" type="xml">
<tree string="Sales Orders" decoration-bf="message_needaction==True" decoration-muted="state=='cancel'" decoration-info="state in ('waiting_date','manual')" decoration-danger="state in ('invoice_except','shipping_except')">
<tree string="Sales Orders" decoration-bf="message_needaction==True" decoration-muted="state=='cancel'">
<field name="message_needaction" invisible="1"/>
<field name="name" string="Order Number"/>
<field name="date_order"/>
<field name="partner_id"/>
<field name="user_id"/>
<field name="amount_total" sum="Total Tax Included" widget="monetary"/>
<field name="state"/>
<field name="invoice_status"/>
<field name="state" invisible="1"/>
</tree>
</field>
</record>
@@ -109,7 +110,7 @@
<field name="model">sale.order</field>
<field name="priority">4</field>
<field name="arch" type="xml">
<tree string="Quotation" decoration-bf="message_needaction==True" decoration-muted="state=='cancel'" decoration-info="state in ('waiting_date','manual')" decoration-danger="state in ('invoice_except','shipping_except')">
<tree string="Quotation" decoration-bf="message_needaction==True" decoration-muted="state=='cancel'">
<field name="message_needaction" invisible="1"/>
<field name="name" string="Quotation Number"/>
<field name="date_order"/>
@@ -126,22 +127,24 @@
<field name="model">sale.order</field>
<field name="arch" type="xml">
<form string="Sales Order">
<header>
<button name="invoice_recreate" states="invoice_except" string="Recreate Invoice" groups="base.group_user"/>
<button name="invoice_corrected" states="invoice_except" string="Ignore Exception" groups="base.group_user"/>
<button name="action_button_confirm" states="sent" string="Confirm Sale" class="oe_highlight" type="object" groups="base.group_user"/>
<button name="action_quotation_send" string="Send by Email" type="object" states="draft" class="oe_highlight" groups="base.group_user"/>
<button name="action_quotation_send" string="Send by Email" type="object" states="sent,progress,manual" groups="base.group_user"/>
<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_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"/>
<button name="cancel" states="draft,sent" string="Cancel" groups="base.group_user"/>
<button name="action_cancel" states="manual,progress" string="Cancel Order" type="object" groups="base.group_user"/>
<button name="invoice_cancel" states="invoice_except" string="Cancel Order" groups="base.group_user"/>
<field name="state" widget="statusbar" statusbar_visible="draft,sent,progress,done" statusbar_colors='{"invoice_except":"red","waiting_date":"blue"}'/>
<header>
<button name="%(action_view_sale_advance_payment_inv)d" string="Create Invoice"
type="action" class="btn-primary"
attrs="{'invisible': [('invoice_status', '!=', 'to invoice')]}"/>
<button name="%(action_view_sale_advance_payment_inv)d" string="Create Invoice"
type="action" context="{'default_advance_payment_method': 'percentage'}"
attrs="{'invisible': ['|',('invoice_status', '!=', 'no'), ('state', '!=', 'sale')]}"/>
<button name="action_quotation_send" string="Send by Email" type="object" states="draft" class="btn-primary"/>
<button name="action_quotation_send" string="Send by Email" type="object" states="sent,sale"/>
<button name="print_quotation" string="Print" type="object" states="draft" class="btn-primary"/>
<button name="print_quotation" string="Print" type="object" states="sent,sale"/>
<button name="action_confirm" states="sent" string="Confirm Sale" class="btn-primary" type="object" context="{'show_sale': True}"/>
<button name="action_confirm" states="draft" string="Confirm Sale" type="object" context="{'show_sale': True}"/>
<button name="action_cancel" states="draft,sent,sale" type="object" string="Cancel"/>
<button name="action_draft" states="cancel" type="object" string="Set to Quotation"/>
<button name="action_done" type="object" string="Set to Done" states="sale"
help="If a sale order is done, you can not modify it manually anymore. But you will still be able to invoice or deliver."/>
<field name="state" widget="statusbar" statusbar_visible="draft,sent,sale,done"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
@@ -149,28 +152,25 @@
type="object"
class="oe_stat_button"
icon="fa-pencil-square-o"
attrs="{'invisible': [('invoice_count', '=', 0)]}" groups="base.group_user">
attrs="{'invisible': [('invoice_count', '=', 0)]}">
<field name="invoice_count" widget="statinfo" string="Invoices"/>
</button>
</div>
<div class="oe_title">
<label string="Quotation" attrs="{'invisible': [('state', 'not in', ('draft', 'sent'))]}"/>
<label string="Sales Order" attrs="{'invisible': [('state', 'in', ('draft', 'sent'))]}"/>
<h1>
<field name="name" class="oe_inline" readonly="1"/>
</h1>
</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}'/>
<field name="partner_id" domain="[('customer','=',True)]" context="{'search_default_customer':1, 'show_address': 1}" options='{"always_reload": True}'/>
<field name="partner_invoice_id" groups="sale.group_delivery_invoice_address" context="{'default_type':'invoice'}"/>
<field name="partner_shipping_id" on_change="onchange_delivery_id(company_id, partner_id, partner_shipping_id, fiscal_position_id)" groups="sale.group_delivery_invoice_address" context="{'default_type':'delivery'}"/>
<field name="project_id" context="{'partner_id':partner_invoice_id, 'manager_id': user_id, 'default_pricelist_id':pricelist_id, 'default_name':name, 'default_type': 'contract'}" groups="sale.group_analytic_accounting" domain="[('type','in',['view','normal','contract'])]"/>
<field name="contract_state" groups="sale.group_analytic_accounting" widget="label_selection" attrs="{'invisible': [('project_id', '=', False)]}" options="{'classes': {'template': 'default', 'draft': 'info', 'open': 'success', 'pending': 'warning', 'close': 'danger', 'cancelled': 'warning'}}" readonly="1"/>
<field name="partner_shipping_id" groups="sale.group_delivery_invoice_address" context="{'default_type':'delivery'}"/>
<field name="project_id" context="{'default_partner_id':partner_invoice_id, 'default_name':name}"/>
</group>
<group>
<field name="date_order"/>
<field domain="[('type','=','sale')]" name="pricelist_id" groups="product.group_sale_pricelist" on_change="onchange_pricelist_id(pricelist_id,order_line)"/>
<field name="date_order" invisible="1"/>
<field domain="[('type','=','sale')]" name="pricelist_id" groups="product.group_sale_pricelist"/>
<field name="currency_id" invisible="1"/>
<field name="validity_date"/>
<field name="payment_term_id" options="{'no_create': True}"/>
@@ -178,31 +178,35 @@
</group>
<notebook>
<page string="Order Lines">
<field name="order_line" mode="tree,kanban">
<field name="order_line" mode="tree,kanban"
attrs="{'readonly': [('state', 'in', ('done','cancel'))]}">
<form string="Sales Order Lines">
<header groups="base.group_user">
<button name="%(action_view_sale_order_line_make_invoice)d" states="confirmed" string="Invoice" type="action" icon="terp-document-new"/>
<field name="state" widget="statusbar" statusbar_visible="draft,confirmed,done" statusbar_colors='{"exception":"red","cancel":"red"}'/>
</header>
<group>
<group>
<field name="product_id"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
groups="base.group_user"
on_change="product_id_change(parent.pricelist_id, product_id, product_uom_qty, False, product_uos_qty, False, name, parent.partner_id, False, True, parent.date_order, False, parent.fiscal_position_id, False, context)"/>
<label for="product_uom_qty"/>
attrs="{'readonly': [('state', 'in', ('sale','done', 'cancel'))]}"
/>
<field name="invoice_status" invisible="1"/>
<field name="qty_to_invoice" invisible="1"/>
<field name="qty_delivered_updateable" invisible="1"/>
<label for="product_uom_qty" string="Ordered Quantity"/>
<div>
<field
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom, 'uom_qty_change':True}"
name="product_uom_qty" class="oe_inline"
on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, False, False, parent.date_order, False, parent.fiscal_position_id, True, context)"/>
name="product_uom_qty" class="oe_inline"/>
<field name="product_uom" groups="product.group_uom" class="oe_inline oe_no_button"
on_change="product_uom_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, False, False, parent.date_order, context)"/>
attrs="{'readonly': [('state', 'in', ('sale','done', 'cancel'))]}"/>
</div>
<label for="product_uos_qty" groups="product.group_uos"/>
<div groups="product.group_uos">
<field name="product_uos_qty" class="oe_inline"/>
<field name="product_uos" options='{"no_open": True}' class="oe_inline"/>
<label for="qty_delivered" string="Delivered Quantity"
invisible="not context.get('show_sale')"/>
<div>
<field name="qty_delivered" invisible="not context.get('show_sale')"
attrs="{'readonly': [('qty_delivered_updateable', '=', False)]}"/>
</div>
<label for="qty_invoiced" string="Invoiced Quantity" invisible="not context.get('show_sale')"/>
<div>
<field name="qty_invoiced" invisible="not context.get('show_sale')"/>
</div>
<field name="price_unit"/>
<label for="discount" groups="sale.group_discount_per_so_line"/>
@@ -212,7 +216,10 @@
</group>
<group>
<field name="tax_id" widget="many2many_tags" domain="[('type_tax_use','=','sale'),('company_id','=',parent.company_id)]"/>
<field name="th_weight"/>
<label for="customer_lead"/>
<div>
<field name="customer_lead" class="oe_inline"/> days
</div>
</group>
</group>
<label for="name"/>
@@ -221,41 +228,43 @@
<label for="invoice_lines"/>
<field name="invoice_lines"/>
</div>
</form>
<tree string="Sales Order Lines" editable="bottom">
<field name="sequence" widget="handle"/>
<field name="state" invisible="1"/>
<field name="th_weight" invisible="1"/>
</form>
<tree string="Sales Order Lines" editable="bottom" decoration-info="invoice_status=='to invoice'">
<field name="sequence" widget="handle"/>
<field name="product_id"
attrs="{'readonly': [('state', 'in', ('sale','done', 'cancel'))]}"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
groups="base.group_user"
on_change="product_id_change(parent.pricelist_id, product_id, product_uom_qty, False, product_uos_qty, False, name, parent.partner_id, False, True, parent.date_order, False, parent.fiscal_position_id, False, context)"/>
/>
<field name="name"/>
<field name="product_uom_qty"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
on_change="product_id_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, product_uos_qty, product_uos, name, parent.partner_id, False, False, parent.date_order, False, parent.fiscal_position_id, True, context)"/>
string="Ordered Qty"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"/>
<field name="qty_delivered" invisible="not context.get('show_sale')"
attrs="{'readonly': [('qty_delivered_updateable', '=', False)]}"/>
<field name="qty_invoiced"
invisible="not context.get('show_sale')"/>
<field name="qty_to_invoice" invisible="1"/>
<field name="product_uom"
on_change="product_uom_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, product_uos_qty, product_uos, name, parent.partner_id, False, False, parent.date_order, context)"
attrs="{'readonly': [('state', 'in', ('sale','done', 'cancel'))]}"
groups="product.group_uom" options='{"no_open": True}'/>
<field name="product_uos_qty" groups="product.group_uos" invisible="1"/>
<field name="product_uos" string="UoS" groups="product.group_uos" invisible="1"/>
<field name="price_unit"/>
<field name="price_unit"
attrs="{'readonly': [('qty_invoiced', '&gt;', 0)]}"/>
<field name="tax_id" widget="many2many_tags" domain="[('type_tax_use','=','sale'),('company_id','=',parent.company_id)]"/>
<field name="discount" groups="sale.group_discount_per_so_line"/>
<field name="price_subtotal" widget="monetary"/>
<field name="qty_delivered_updateable" invisible="1"/>
<field name="state" invisible="1"/>
<field name="invoice_status" invisible="1"/>
</tree>
<kanban class="o_kanban_mobile">
<field name="product_id"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
groups="base.group_user"
on_change="product_id_change(parent.pricelist_id, product_id, product_uom_qty, False, product_uos_qty, False, name, parent.partner_id, False, True, parent.date_order, False, parent.fiscal_position_id, False, context)"/>
/>
<field name="product_uom_qty"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
on_change="product_id_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, product_uos_qty, product_uos, name, parent.partner_id, False, False, parent.date_order, False, parent.fiscal_position_id, True, context)"/>
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"/>
<field name="product_uom"
on_change="product_uom_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, product_uos_qty, product_uos, name, parent.partner_id, False, False, parent.date_order, context)"
groups="product.group_uom" options='{"no_open": True}'/>
<field name="product_uos_qty" groups="product.group_uos" invisible="1"/>
<field name="price_subtotal"/>
<templates>
<t t-name="kanban-box">
@@ -283,36 +292,36 @@
<field name="amount_tax" widget='monetary' options="{'currency_field': 'currency_id'}"/>
<div class="oe_subtotal_footer_separator oe_inline">
<label for="amount_total" />
<button name="button_dummy"
states="draft,sent" string="(update)" type="object" class="oe_edit_only oe_link"/>
<!-- <button name="button_dummy"
states="draft,sent" string="(update)" type="object" class="oe_edit_only oe_link"/> -->
</div>
<field name="amount_total" nolabel="1" class="oe_subtotal_footer_separator" widget='monetary' options="{'currency_field': 'currency_id'}"/>
</group>
<field name="note" class="oe_inline" placeholder="An administrator can set up default Terms and conditions in your Company settings."/>
<field name="note" class="oe_inline" placeholder="Setup default terms and conditions in your company settings."/>
<div class="oe_clear"/>
</page>
<page string="Other Information" groups="base.group_user">
<page string="Other Information">
<group>
<group string="Sales Information" name="sales_person" groups="base.group_user">
<group string="Sales Information" name="sales_person">
<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}"/>
<field name="client_order_ref"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
</group>
<group name="sale_pay" string="Invoicing">
<field name="fiscal_position_id" options="{'no_create': True}"
on_change="onchange_fiscal_position(fiscal_position_id, order_line, context)"/>
<field name="fiscal_position_id" options="{'no_create': True}"/>
<field name="invoice_status"
attrs="{'invisible': [('state', 'not in', ('sale','done'))]}"/>
</group>
<group string="Reporting" name="technical" groups="base.group_no_one">
<field groups="base.group_no_one" name="origin"/>
<field groups="base.group_no_one" name="invoiced"/>
</group>
</group>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
@@ -344,12 +353,13 @@
<field name="team_id" string="Sales Team"/>
<field name="project_id"/>
<field name="product_id"/>
<filter string="My" domain="[('user_id','=',uid)]" name="my_sale_orders_filter"/>
<filter string="My Orders" domain="[('user_id','=',uid)]" name="my_sale_orders_filter"/>
<separator/>
<filter string="Quotations" name="draft" domain="[('state','in',('draft','sent'))]" help="Sales Order that haven't yet been confirmed"/>
<filter string="Sales" name="sales" domain="[('state','in',('manual','progress'))]"/>
<filter string="To Invoice" domain="[('state','=','manual')]" help="Sales Order ready to be invoiced"/>
<filter string="Done" domain="[('state','=','done')]" help="Sales Order done"/>
<filter string="Sales" name="sales" domain="[('state','in',('progress','Done'))]"/>
<separator/>
<filter string="To Invoice" domain="[('invoice_status','=','to invoice')]"/>
<filter string="Upselling" domain="[('invoice_status','=','upselling')]"/>
<separator/>
<filter string="Important Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
<group expand="0" string="Group By">
@@ -368,7 +378,7 @@
<field name="view_type">form</field>
<field name="view_mode">tree,kanban,form,calendar,pivot,graph</field>
<field name="search_view_id" ref="view_sales_order_filter"/>
<field name="context">{}</field>
<field name="context">{'show_sale': True}</field>
<field name="domain">[('state', 'not in', ('draft', 'sent', 'cancel'))]</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
@@ -381,28 +391,37 @@
</field>
</record>
<menuitem action="action_orders" id="menu_sale_order" parent="base.menu_sales" sequence="12" groups="base.group_sale_salesman,base.group_sale_manager"/>
<menuitem action="action_orders"
id="menu_sale_order" parent="base.menu_sales"
sequence="12" groups="base.group_sale_salesman,base.group_sale_manager"/>
<record id="action_orders_exception" model="ir.actions.act_window">
<field name="name">Sales in Exception</field>
<record id="action_orders_to_invoice" model="ir.actions.act_window">
<field name="name">Sales to Invoice</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.order</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar,graph</field>
<field name="domain">[('state','in',('shipping_except','invoice_except'))]</field>
<field name="filter" eval="True"/>
<field name="search_view_id" ref="view_sales_order_filter"/>
<field name="view_mode">tree,form,calendar,graph,pivot</field>
<field name="domain">[('invoice_status','=','to invoice')]</field>
</record>
<menuitem name="Invoicing"
id="menu_sale_invoicing" parent="base.menu_base_partner"
sequence="5"/>
<menuitem action="action_orders_to_invoice"
id="menu_sale_order_invoice" parent="sale.menu_sale_invoicing"
sequence="2"/>
<record id="action_orders_in_progress" model="ir.actions.act_window">
<field name="name">Sales Order in Progress</field>
<record id="action_orders_upselling" model="ir.actions.act_window">
<field name="name">Upselling Opportunities</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.order</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar,graph</field>
<field name="domain">[('state','in',('progress','waiting_date','manual'))]</field>
<field name="search_view_id" ref="view_sales_order_filter"/>
<field name="view_mode">tree,form,calendar,graph,pivot</field>
<field name="domain">[('invoice_status','=','upselling')]</field>
<field name="context">{'show_sale': True}</field>
</record>
<menuitem action="action_orders_upselling"
id="menu_sale_order_upselling" parent="sale.menu_sale_invoicing"
sequence="5"/>
<record id="action_quotations" model="ir.actions.act_window">
@@ -433,18 +452,6 @@
action="action_quotations" parent="base.menu_sales"
sequence="11"/>
<record id="action_order_tree" model="ir.actions.act_window">
<field name="name">Old Quotations</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.order</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar,graph</field>
<field name="domain">[('state','=','draft'),('date_order','&lt;',time.strftime('%Y-%m-%d %H:%M:%S'))]</field>
<field name="filter" eval="True"/>
<field name="search_view_id" ref="view_sales_order_filter"/>
</record>
<record id="view_order_line_tree" model="ir.ui.view">
<field name="name">sale.order.line.tree</field>
<field name="model">sale.order.line</field>
@@ -454,63 +461,23 @@
<field name="order_id"/>
<field name="order_partner_id"/>
<field name="name"/>
<field name="product_uom_qty" string="Qty"/>
<field name="product_uom" string="Unit of Measure" groups="product.group_uom"/>
<field name="salesman_id"/>
<field name="product_uom_qty" string="Qty"/>
<field name="qty_delivered"/>
<field name="qty_invoiced"/>
<field name="qty_to_invoice"/>
<field name="product_uom" string="Unit of Measure" groups="product.group_uom"/>
<field name="price_subtotal" sum="Total" widget="monetary"/>
<field name="state"/>
<field name="invoiced"/>
</tree>
</field>
</record>
<record id="view_order_line_form2" model="ir.ui.view">
<field name="name">sale.order.line.form2</field>
<field name="model">sale.order.line</field>
<field name="arch" type="xml">
<form string="Sales Order Lines" create="false">
<header>
<button name="%(action_view_sale_order_line_make_invoice)d" string="Create Invoice" type="action" attrs="{'invisible': ['|',('invoiced', '=', 1), ('state', 'not in', ('confirmed', 'draft'))]}" class="oe_highlight" groups="base.group_user"/>
<button name="button_cancel" string="Cancel Line" type="object" states="confirmed,exception" groups="base.group_user"/>
<button name="button_done" string="Done" type="object" attrs="{'invisible': ['|',('invoiced', '=', 0), ('state', 'not in', ('confirmed', 'exception'))]}" class="oe_highlight" groups="base.group_user"/>
<field name="state" widget="statusbar" statusbar_visible="draft,confirmed,done" statusbar_colors='{"exception":"red","cancel":"red"}'/>
</header>
<sheet>
<label for="order_id" class="oe_edit_only"/>
<h1><field name="order_id" domain="[('state','!=','done')]"/></h1>
<label for="order_partner_id" class="oe_edit_only"/>
<h2><field name="order_partner_id"/></h2>
<group>
<group>
<field name="product_id"/>
<label for="product_uom_qty"/>
<div>
<field name="product_uom_qty" readonly="1" class="oe_inline"/>
<field name="product_uom" groups="product.group_uom" class="oe_inline"/>
</div>
</group>
<group>
<field name="price_unit"/>
<field name="discount" groups="sale.group_discount_per_so_line"/>
<field name="price_subtotal" widget="monetary"/>
<field name="invoiced"/>
<field name="company_id" groups="base.group_multi_company" readonly="1"/>
</group>
</group>
<label for="name"/>
<field name="name"/>
</sheet>
</form>
</field>
</record>
<record id="view_sales_order_line_filter" model="ir.ui.view">
<field name="name">sale.order.line.select</field>
<field name="model">sale.order.line</field>
<field name="arch" type="xml">
<search string="Search Sales Order">
<filter string="To Invoice" domain="[('invoiced','&lt;&gt;', 1),('state','=','done')]" help="Sales Order Lines ready to be invoiced"/>
<separator/>
<filter string="Confirmed" domain="[('state', 'in', ['confirmed', 'done'])]" name="confirmed"/>
<filter string="To Invoice" domain="[('qty_to_invoice','&lt;&gt;', 0)]" help="Sales Order Lines ready to be invoiced"/>
<separator/>
<filter string="My Sales Order Lines" domain="[('salesman_id','=',uid)]" help="Sales Order Lines related to a Sales Order of mine"/>
<field name="order_id"/>
@@ -521,77 +488,40 @@
<filter string="Product" domain="[]" context="{'group_by':'product_id'}"/>
<filter string="Order" domain="[]" context="{'group_by':'order_id'}"/>
<filter string="Salesperson" domain="[]" context="{'group_by':'salesman_id'}"/>
<filter string="Status" domain="[]" context="{'group_by':'state'}"/>
</group>
</search>
</field>
</record>
<record id="view_sales_order_uninvoiced_line_filter" model="ir.ui.view">
<field name="name">sale.order.uninvoiced.line</field>
<field name="model">sale.order.line</field>
<field name="arch" type="xml">
<search string="Search Uninvoiced Lines">
<filter string="To Do" domain="[('state','=','confirmed')]" name="sale order" help="Confirmed sales order lines, not yet delivered"/>
<filter string="Done" domain="[('state','=','done')]" name="sale_order_done" help="Sales order lines done"/>
<filter string="Shipped" domain="[('state','=','done')]" name="unshipped" help="Sales Order Lines that are in 'done' state"/>
<separator/>
<filter string="Uninvoiced" name="uninvoiced" domain="[('invoiced','&lt;&gt;', 1),('state','&lt;&gt;','draft'),('state','&lt;&gt;','cancel')]" help="Sales Order Lines that are confirmed, done or in exception state and haven't yet been invoiced"/>
<separator/>
<filter string="My Sales Order Lines" domain="[('salesman_id','=',uid)]" help="My Sales Order Lines"/>
<field name="order_id"/>
<field name="order_partner_id" operator="child_of"/>
<field name="product_id"/>
<field name="salesman_id"/>
<group expand="0" string="Group By">
<filter string="Order" domain="[]" context="{'group_by':'order_id'}" help="Order reference"/>
<filter string="Product" domain="[]" context="{'group_by':'product_id'}"/>
<filter string="Status" domain="[]" context="{'group_by':'state'}"/>
</group>
</search>
</field>
<record id="action_product_sale_list" model="ir.actions.act_window">
<field name="name">Sale Order Lines</field>
<field name="res_model">sale.order.line</field>
<field name="context">{'search_default_product_id': [active_id], 'default_product_id': active_id}</field>
<field name="domain">[('state', 'in', ['sale', 'done'])]</field>
</record>
<record id="action_order_line_tree2" model="ir.actions.act_window">
<field name="name">Order Lines to Invoice</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.order.line</field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="search_view_id" ref="view_sales_order_uninvoiced_line_filter"/>
<field name="context">{"search_default_uninvoiced":1}</field>
<field name="filter" eval="True"/>
<field name="help" type="html">
<p>
Here is a list of each sales order line to be invoiced. You can
invoice sales orders partially, by lines of sales order. You do
not need this list if you invoice from the delivery orders or
if you invoice sales totally.
</p>
</field>
</record>
<record id="action_order_line_tree3" model="ir.actions.act_window">
<field name="name">Uninvoiced and Delivered Lines</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.order.line</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoiced','&lt;&gt;', 1),('state','=','done')]</field>
<field name="filter" eval="True"/>
</record>
<record id="action_order_line_product_tree" model="ir.actions.act_window">
<field name="context">{}</field><!-- force empty -->
<field name="name">Sales Order Lines</field>
<field name="res_model">sale.order.line</field>
<field name="view_id" ref="view_order_line_tree"/>
<field name="context">{'search_default_confirmed': 1}</field>
</record>
<record model="ir.ui.view" id="product_form_view_sale_order_button">
<field name="name">product.product.sale.order</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="groups_id" eval="[(4, ref('base.group_sale_salesman'))]"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<button class="oe_stat_button" name="%(action_product_sale_list)d"
type="action" icon="fa-usd"
groups="base.group_no_one">
<field string="Sales" name="sales_count" widget="statinfo" />
</button>
</div>
</field>
</record>
<record model="ir.ui.view" id="product_template_form_view_sale_order_button">
<field name="name">product.template.sale.order.button</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="groups_id" eval="[(4, ref('base.group_sale_salesman'))]"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<button class="oe_stat_button" name="action_view_sales"
@@ -603,23 +533,20 @@
</field>
</record>
<record model="ir.ui.view" id="product_template_form_view_sale_order_button">
<field name="name">product.template.sale.order.button</field>
<record model="ir.ui.view" id="product_template_form_view_invoice_policy">
<field name="name">product.template.invoice.policy</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="groups_id" eval="[(4, ref('base.group_sale_salesman'))]"/>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<button class="oe_stat_button" name="action_view_sales"
type="object" icon="fa-usd"
groups="base.group_no_one">
<field string="Sales" name="sales_count" widget="statinfo" />
</button>
</div>
<field name="type" position="after">
<field name="invoice_policy" widget="radio"/>
<field name="track_service" widget="radio" invisible="True"/>
</field>
</field>
</record>
<record model="ir.ui.view" id="view_company_inherit_form2">
<field name="name">res.company.form.inherit</field>
<field name="inherit_id" ref="base.view_company_form"/>
@@ -672,6 +599,7 @@
<field name="search_view_id" ref="sale.view_sales_order_filter"/>
<field name="domain">[('state','not in',('draft','sent','cancel'))]</field>
<field name="context">{
'show_sale': True,
'search_default_team_id': [active_id],
'default_team_id': active_id,
}
@@ -693,8 +621,9 @@
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar,graph</field>
<field name="search_view_id" ref="sale.view_sales_order_filter"/>
<field name="domain">[('state', '=', 'manual')]</field>
<field name="domain">[('state', '=', 'sale'),('invoice_status','=','to invoice')]</field>
<field name="context">{
'show_sale': True,
'search_default_team_id': [active_id],
'default_team_id': active_id,
}
-303
View File
@@ -1,303 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="wkf_sale" model="workflow">
<field name="name">sale.order.basic</field>
<field name="osv">sale.order</field>
<field name="on_create">True</field>
</record>
<!-- Activity -->
<record id="act_draft" model="workflow.activity">
<field name="wkf_id" ref="wkf_sale"/>
<field name="flow_start">True</field>
<field name="name">draft</field>
</record>
<record id="act_sent" model="workflow.activity">
<field name="wkf_id" ref="wkf_sale"/>
<field name="name">sent</field>
<field name="kind">function</field>
<field name="action">write({'state':'sent'})</field>
</record>
<record id="act_router" model="workflow.activity">
<field name="wkf_id" ref="wkf_sale"/>
<field name="name">router</field>
<field name="kind">function</field>
<field name="action">action_wait()</field>
<field name="split_mode">OR</field>
</record>
<record id="act_wait_invoice" model="workflow.activity">
<field name="wkf_id" ref="wkf_sale"/>
<field name="name">wait_invoice</field>
</record>
<record id="act_done" model="workflow.activity">
<field name="wkf_id" ref="wkf_sale"/>
<field name="name">done</field>
<field name="flow_stop">True</field>
<field name="kind">function</field>
<field name="action">action_done()</field>
<field name="join_mode">AND</field>
</record>
<record id="act_cancel" model="workflow.activity">
<field name="wkf_id" ref="wkf_sale"/>
<field name="name">cancel</field>
<field name="flow_stop">True</field>
<field name="kind">stopall</field>
<field name="action">action_cancel()</field>
</record>
<record id="act_cancel2" model="workflow.activity">
<field name="wkf_id" ref="wkf_sale"/>
<field name="name">cancel2</field>
<field name="flow_stop">True</field>
<field name="kind">stopall</field>
<field name="action">action_cancel()</field>
</record>
<record id="act_invoice" model="workflow.activity">
<field name="wkf_id" ref="wkf_sale"/>
<field name="name">invoice</field>
<field name="kind">subflow</field>
<field name="subflow_id" search="[('name','=','account.invoice.basic')]"/>
<field name="action">action_invoice_create()</field>
</record>
<record id="act_invoice_except" model="workflow.activity">
<field name="wkf_id" ref="wkf_sale"/>
<field name="name">invoice_except</field>
<field name="kind">function</field>
<field name="action">action_invoice_cancel()</field>
</record>
<record id="act_invoice_end" model="workflow.activity">
<field name="wkf_id" ref="wkf_sale"/>
<field name="name">invoice_end</field>
<field name="kind">function</field>
<field name="action">action_invoice_end()</field>
</record>
<record id="act_invoice_cancel" model="workflow.activity">
<field name="wkf_id" ref="wkf_sale"/>
<field name="name">invoice_cancel</field>
<field name="flow_stop">True</field>
<field name="kind">stopall</field>
<field name="action">action_cancel()</field>
</record>
<!-- Transistion -->
<record id="trans_draft_sent" model="workflow.transition">
<field name="act_from" ref="act_draft"/>
<field name="act_to" ref="act_sent"/>
<field name="signal">quotation_sent</field>
</record>
<record id="trans_draft_router" model="workflow.transition">
<field name="act_from" ref="act_draft"/>
<field name="act_to" ref="act_router"/>
<field name="signal">order_confirm</field>
</record>
<record id="trans_draft_cancel" model="workflow.transition">
<field name="act_from" ref="act_draft"/>
<field name="act_to" ref="act_cancel"/>
<field name="signal">cancel</field>
</record>
<record id="trans_sent_router" model="workflow.transition">
<field name="act_from" ref="act_sent"/>
<field name="act_to" ref="act_router"/>
<field name="signal">order_confirm</field>
</record>
<record id="trans_sent_cancel" model="workflow.transition">
<field name="act_from" ref="act_sent"/>
<field name="act_to" ref="act_cancel"/>
<field name="signal">cancel</field>
</record>
<record id="trans_router_wait_invoice" model="workflow.transition">
<field name="act_from" ref="act_router"/>
<field name="act_to" ref="act_wait_invoice"/>
</record>
<record id="trans_wait_invoice_all_lines_invoiced" model="workflow.transition">
<field name="act_from" ref="act_wait_invoice"/>
<field name="act_to" ref="act_invoice_end"/>
<field name="signal">all_lines</field>
</record>
<record id="trans_wait_invoice_cancel2" model="workflow.transition">
<field name="act_from" ref="act_wait_invoice"/>
<field name="act_to" ref="act_cancel2"/>
<field name="signal">cancel</field>
</record>
<record id="trans_wait_invoice_invoice_manual" model="workflow.transition">
<field name="act_from" ref="act_wait_invoice"/>
<field name="act_to" ref="act_invoice"/>
<field name="signal">manual_invoice</field>
</record>
<record id="trans_invoice_invoice_end" model="workflow.transition">
<field name="act_from" ref="act_invoice"/>
<field name="act_to" ref="act_invoice_end"/>
<field name="signal">subflow.paid</field>
</record>
<record id="trans_invoice_invoice_except" model="workflow.transition">
<field name="act_from" ref="act_invoice"/>
<field name="act_to" ref="act_invoice_except"/>
<field name="signal">subflow.cancel</field>
</record>
<record id="trans_invoice_except_invoice" model="workflow.transition">
<field name="act_from" ref="act_invoice_except"/>
<field name="act_to" ref="act_invoice"/>
<field name="signal">invoice_recreate</field>
</record>
<record id="trans_invoice_except_invoice_end" model="workflow.transition">
<field name="act_from" ref="act_invoice_except"/>
<field name="act_to" ref="act_invoice_end"/>
<field name="signal">invoice_corrected</field>
</record>
<record id="trans_invoice_except_invoice_cancel" model="workflow.transition">
<field name="act_from" ref="act_invoice_except"/>
<field name="act_to" ref="act_invoice_cancel"/>
<field name="signal">invoice_cancel</field>
</record>
<record id="trans_invoice_end_done" model="workflow.transition">
<field name="act_from" ref="act_invoice_end"/>
<field name="act_to" ref="act_done"/>
</record>
<!--
Procurements creation and checking branch
-->
<!-- Activity -->
<record id="act_wait_ship" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">wait_ship</field>
</record>
<record id="act_cancel3" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">cancel3</field>
<field name="flow_stop">True</field>
<field name="kind">stopall</field>
<field name="action">action_cancel()</field>
</record>
<record id="act_ship" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship</field>
<field name="kind">function</field>
<field name="action">action_ship_create()</field>
</record>
<record id="act_ship_ignore" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship_ignore</field>
<field name="kind">function</field>
<field name="action">action_ignore_delivery_exception()</field>
</record>
<record id="act_ship_end" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship_end</field>
<field name="kind">dummy</field>
</record>
<record id="act_ship_cancel" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship_cancel</field>
<field name="flow_stop">True</field>
<field name="kind">stopall</field>
<field name="action">action_cancel()</field>
</record>
<record id="act_ship_except" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship_except</field>
<field name="kind">function</field>
<field name="action">write({'state':'shipping_except'})</field>
</record>
<!-- Transition -->
<record id="trans_router_wait_ship" model="workflow.transition">
<field name="act_from" ref="sale.act_router"/>
<field name="act_to" ref="act_wait_ship"/>
</record>
<record id="trans_router_wait_invoice_shipping" model="workflow.transition">
<field name="act_from" ref="sale.act_wait_invoice"/>
<field name="act_to" ref="sale.act_invoice_end"/>
<field name="condition">(order_policy=='picking')</field>
</record>
<record id="trans_wait_invoice_invoice" model="workflow.transition">
<field name="act_from" ref="sale.act_wait_invoice"/>
<field name="act_to" ref="sale.act_invoice"/>
<field name="condition">order_policy=='prepaid'</field>
</record>
<record id="trans_wait_ship_cancel3" model="workflow.transition">
<field name="act_from" ref="act_wait_ship"/>
<field name="act_to" ref="act_cancel3"/>
<field name="signal">cancel</field>
</record>
<record id="trans_wait_ship_ship" model="workflow.transition">
<field name="act_from" ref="act_wait_ship"/>
<field name="act_to" ref="act_ship"/>
<field name="condition">procurement_needed() and ((order_policy!='prepaid') or invoiced)</field>
</record>
<record id="trans_wait_ship_done" model="workflow.transition">
<field name="act_from" ref="act_wait_ship"/>
<field name="act_to" ref="act_ship_end"/>
<field name="condition">not procurement_needed()</field>
</record>
<record id="trans_ship_end_done" model="workflow.transition">
<field name="act_from" ref="act_ship_end"/>
<field name="act_to" ref="sale.act_done"/>
</record>
<record id="trans_ship_ship_end" model="workflow.transition">
<field name="act_from" ref="act_ship"/>
<field name="act_to" ref="act_ship_end"/>
<field name="signal">ship_end</field>
<field name="trigger_model" eval="False"/> <!-- Force empty -->
<field name="trigger_expr_id" eval="False"/> <!-- Force empty -->
<field name="condition" eval="True"/> <!-- Force empty -->
</record>
<record id="trans_ship_ship_except" model="workflow.transition">
<field name="act_from" ref="act_ship"/>
<field name="act_to" ref="act_ship_except"/>
<field name="signal">ship_except</field>
<field name="condition" eval="True"/> <!-- Force empty -->
</record>
<record id="trans_ship_except_ship" model="workflow.transition">
<field name="act_from" ref="act_ship_except"/>
<field name="act_to" ref="act_ship"/>
<field name="signal">ship_recreate</field>
</record>
<record id="trans_ship_except_ship_ignore" model="workflow.transition">
<field name="act_from" ref="act_ship_except"/>
<field name="act_to" ref="act_ship_ignore"/>
<field name="signal">ship_corrected</field>
</record>
<record id="trans_ship_ignore_ship_end" model="workflow.transition">
<field name="act_from" ref="act_ship_ignore"/>
<field name="act_to" ref="act_ship_end"/>
</record>
<record id="trans_ship_except_ship_cancel" model="workflow.transition">
<field name="act_from" ref="act_ship_except"/>
<field name="act_to" ref="act_ship_cancel"/>
<field name="signal">ship_cancel</field>
</record>
</data>
</openerp>
-82
View File
@@ -1,82 +0,0 @@
-
Salesman can also cancel order therefore test with that user which have salesman rights,
-
!context
uid: 'res_users_salesman'
-
In order to test the cancel sale order.
I confirm order (with at least 2 lines)
-
!workflow {model: sale.order, action: order_confirm, ref: sale_order_8}
-
I check state of order in 'Sale Order'.
-
!assert {model: sale.order, id: sale_order_8, string: Sale order should be In Progress state}:
- state == 'manual'
-
I check that Invoice should not be created.
-
!python {model: sale.order}: |
sale_order = self.browse(cr, uid, ref("sale_order_8"))
assert len(sale_order.invoice_ids) == False, "Invoice should not be created."
-
I create an invoice for the first line
-
!python {model: sale.order.line.make.invoice}: |
ctx = context.copy()
ctx.update({"active_model": 'sale.order.line', "active_ids": [ref("sale_order_line_20")], "active_id":ref("sale_order_line_20")})
pay_id = self.create(cr, uid, {})
self.make_invoices(cr, uid, [pay_id], context=ctx)
invoice_ids = self.pool.get('sale.order').browse(cr, uid, ref("sale_order_8")).invoice_ids
-
I create an invoice for a fixed price (25% of the second line, thus 5)
-
!python {model: sale.advance.payment.inv}: |
ctx = context.copy()
ctx.update({"active_model": 'sale.order', "active_ids": [ref("sale_order_8")], "active_id":ref("sale_order_8")})
pay_id = self.create(cr, uid, {'advance_payment_method': 'fixed', 'amount': 5, 'product_id': ref("sale_order_line_21")})
self.create_invoices(cr, uid, [pay_id], context=ctx)
invoice_ids = self.pool.get('sale.order').browse(cr, uid, ref("sale_order_8")).invoice_ids
-
I create an invoice for the remaining and check the amount (should be the remaining amount of second line)
-
!python {model: sale.advance.payment.inv}: |
ctx = context.copy()
ctx.update({"active_model": 'sale.order', "active_ids": [ref("sale_order_8")], "active_id":ref("sale_order_8")})
pay_id = self.create(cr, uid, {'advance_payment_method': 'all'})
self.create_invoices(cr, uid, [pay_id], context=ctx)
invoice_ids = self.pool.get('sale.order').browse(cr, uid, ref("sale_order_8")).invoice_ids
assert len(invoice_ids) == 3, "All invoices are not created"
for invoice in invoice_ids:
assert invoice.amount_total in (7290,5,20), "Invoice total is not correct"
-
I cancel all the invoices.
-
!python {model: sale.order}: |
invoice_ids = self.browse(cr, uid, ref("sale_order_8")).invoice_ids
for invoice in invoice_ids:
invoice.signal_workflow('invoice_cancel')
-
I check order status in "Invoice Exception" and related invoice is in cancel state.
-
!assert {model: sale.order, id: sale_order_8, string: Sale order should be in Invoice Exception state}:
- state == "invoice_except", "Order should be in Invoice Exception state after cancel Invoice"
-
I click recreate invoice.
-
!workflow {model: sale.order, action: invoice_recreate, ref: sale_order_8}
-
I check that the invoice is correctly created with all lines.
-
!python {model: sale.order}: |
sale_order = self.browse(cr, uid, ref("sale_order_8"))
total_order_line = 0
assert len(sale_order.invoice_ids), "Invoice should be created."
for invoice in sale_order.invoice_ids:
if invoice.state != 'cancel':
total_order_line += len(invoice.invoice_line_ids)
assert total_order_line == 2, "wrong number of invoice lines, got %s" % total_order_line
-60
View File
@@ -1,60 +0,0 @@
-
I create a draft Sale Order with 2 lines but 1 canceled in order to check if the canceled lines are not considered in the logic
-
!record {model: sale.order, id: sale_order_cl_2}:
partner_id: base.res_partner_3
partner_invoice_id: base.res_partner_address_25
partner_shipping_id: base.res_partner_address_25
pricelist_id: product.list0
order_policy: manual
-
!record {model: sale.order.line, id: sale_order_cl_2_line_1}:
order_id: sale_order_cl_2
product_id: product.product_product_27
product_uom_qty: 1
product_uom: 1
price_unit: 3645
name: 'Laptop Customized'
-
!record {model: sale.order.line, id: sale_order_cl_2_line_2}:
order_id: sale_order_cl_2
product_id: product.product_product_12
product_uom_qty: 1
product_uom: 1
price_unit: 12.50
name: 'Mouse, Wireless'
-
I cancel the first line
-
!python {model: sale.order.line, id: sale_order_cl_2_line_1}: |
self.button_cancel()
-
I confirm the sale order
-
!workflow {model: sale.order, action: order_confirm, ref: sale_order_cl_2}
-
Invoice the whole sale order
-
!python {model: sale.advance.payment.inv}: |
ctx = context.copy()
ctx.update({"active_model": 'sale.order',
"active_ids": [ref("sale_order_cl_2")],
"active_id":ref("sale_order_cl_2")})
pay_id = self.create(cr, uid, {'advance_payment_method': 'all'})
self.create_invoices(cr, uid, [pay_id], context=ctx)
-
I check the invoice
-
!python {model: sale.order, id: sale_order_cl_2}: |
invoice = self.invoice_ids
assert len(invoice.invoice_line_ids) == 1, "Only 1 line should be invoiced because the other one is canceled, got %d" % len(invoice.invoice_line_ids)
-
I set the sale to done
-
!python {model: sale.order, id: sale_order_cl_2}: |
self.action_done()
-
And check if the canceled line is still canceled
-
!assert {model: sale.order.line, id: sale_order_cl_2_line_1, string: The canceled line should still be canceled}:
- state == 'cancel'
-28
View File
@@ -1,28 +0,0 @@
-
Create a user as 'Salesmanager'
-
!record {model: res.users, id: res_users_salesmanager, view: False}:
company_id: base.main_company
name: Sales manager
login: sm
email: salesmanager@yourcompany.com
-
I added groups for Salesmanager.
-
!record {model: res.users, id: res_users_salesmanager}:
groups_id:
- base.group_sale_manager
-
Create a user as 'Salesman'
-
!record {model: res.users, id: res_users_salesman, view: False}:
company_id: base.main_company
name: Salesman
login: su
email: salesman@yourcompany.com
-
I added groups for Salesman.
-
!record {model: res.users, id: res_users_salesman}:
groups_id:
- base.group_sale_salesman_all_leads
-19
View File
@@ -1,19 +0,0 @@
-
Sales manager can only delete order therefore test with that user which have sales manager rights,
-
!context
uid: 'res_users_salesmanager'
-
I try to delete In progress order and check Error Message.
-
!python {model: sale.order}: |
try:
self.unlink(cr, uid, [ref("sale_order_7")])
except Exception,e:
pass
-
I make duplicate order and delete.
-
!python {model: sale.order}: |
id = self.copy(cr, uid, ref('sale_order_7'))
self.unlink(cr, uid, [id])
-66
View File
@@ -1,66 +0,0 @@
-
I confirm the Quotation with "On Demand" order policy.
-
!workflow {model: sale.order, action: order_confirm, ref: sale_order_2}
-
I check that Invoice should not created.
-
!python {model: sale.order}: |
sale_order = self.browse(cr, uid, ref("sale_order_2"))
assert len(sale_order.invoice_ids) == 0, "Invoice should not created."
-
I create advance invoice where type is 'Fixed Price'.
-
!python {model: sale.advance.payment.inv}: |
ctx = context.copy()
ctx.update({"active_model": 'sale.order', "active_ids": [ref("sale_order_2")], "active_id":ref("sale_order_2")})
order_line = self.pool.get('sale.order.line').browse(cr, uid, ref("sale_order_line_4"), context=context)
pay_id = self.create(cr, uid, {'advance_payment_method': 'fixed', 'product_id': order_line.product_id.id, 'amount': order_line.price_unit})
self.create_invoices(cr, uid, [pay_id], context=ctx)
-
I check Invoice which made advance.
-
!python {model: sale.order}: |
order = self.browse(cr, uid, ref('sale_order_2'))
assert order.invoice_ids, "Invoice should be created after make advance invoice."
-
I create advance invoice where type is 'Invoice all the Sale Order'.
-
!python {model: sale.advance.payment.inv}: |
ctx = context.copy()
ctx.update({"active_model": 'sale.order', "active_ids": [ref("sale_order_2")], "active_id":ref("sale_order_2")})
pay_id = self.create(cr, uid, {'advance_payment_method': 'all'})
self.create_invoices(cr, uid, [pay_id], context=ctx)
-
I check Invoice which made advance where type is 'Invoice all the Sale Order'.
-
!python {model: sale.order}: |
order = self.browse(cr, uid, ref('sale_order_2'))
assert order.invoice_ids, "Invoice should be created after make advance invoice where type is 'Invoice all the Sale Order'."
-
I open the Invoice.
-
!python {model: sale.order}: |
so = self.browse(cr, uid, ref("sale_order_2"))
account_invoice_obj = self.pool.get('account.invoice')
for invoice in so.invoice_ids:
invoice.signal_workflow('invoice_open')
-
I pay the invoice.
-
!python {model: account.invoice}: |
sale_order = self.pool.get('sale.order')
order = sale_order.browse(cr, uid, ref("sale_order_2"))
journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'cash'), ('company_id', '=', order.company_id.id)], limit=1)
import time
for invoice in order.invoice_ids:
self.pay_and_reconcile(cr, uid, [invoice.id], journal_ids[0])
-
I check Invoice after do manual.
-
!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_count, "Order is not invoiced."
assert sale_order.invoiced, "Order is not paid."
assert sale_order.state == 'done', 'Order should be Done.'
-46
View File
@@ -1,46 +0,0 @@
-
Test the data with salesman,
-
!context
uid: 'res_users_salesman'
-
In order to test process of the Sale Order, I create sale order
-
!record {model: sale.order, id: sale_order_test1}:
partner_id: base.res_partner_2
note: Invoice after delivery
payment_term_id: account.account_payment_term
order_line:
- product_id: product.product_product_7
product_uom_qty: 8
-
I verify that the onchange was correctly triggered
-
!python {model: sale.order}: |
from openerp.tools import float_compare
order_line = self.browse(cr, uid, ref('sale.sale_order_test1')).order_line
assert order_line[0].name == u'[A8767] Apple In-Ear Headphones', "The onchange function of product was not correctly triggered"
assert float_compare(order_line[0].price_unit, 79.0, precision_digits=2) == 0, "The onchange function of product was not correctly triggered"
assert order_line[0].product_uom_qty == 8, "The onchange function of product was not correctly triggered"
assert order_line[0].product_uom.id == ref('product.product_uom_unit'), "The onchange function of product was not correctly triggered"
-
I create another sale order
-
!record {model: sale.order, id: sale_order_test2}:
partner_id: base.res_partner_2
order_line:
- product_id: product.product_product_7
product_uom_qty: 16
product_uom: product.product_uom_dozen
-
I verify that the onchange was correctly triggered
-
!python {model: sale.order}: |
from openerp.tools import float_compare
order_line = self.browse(cr, uid, ref('sale.sale_order_test2')).order_line
assert order_line[0].name == u'[A8767] Apple In-Ear Headphones', "The onchange function of product was not correctly triggered"
assert float_compare(order_line[0].price_unit, 79.0 * 12, precision_digits=2) == 0, "The onchange function of product was not correctly triggered"
assert order_line[0].product_uom.id == ref('product.product_uom_dozen'), "The onchange function of product was not correctly triggered"
assert order_line[0].product_uom_qty == 16, "The onchange function of product was not correctly triggered"
+2 -2
View File
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_sale_to_invoice
import test_sale_to_invoice
import test_sale_order
+38
View File
@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.tests import common
class TestSale(common.TransactionCase):
def setUp(self):
super(TestSale, self).setUp()
# some users
group_manager = self.env.ref('base.group_sale_manager')
group_user = self.env.ref('base.group_sale_salesman')
self.manager = self.env['res.users'].create({
'name': 'Andrew Manager',
'login': 'manager',
'alias_name': 'andrew',
'email': 'a.m@example.com',
'signature': '--\nAndreww',
'notify_email': 'always',
'groups_id': [(6, 0, [group_manager.id])]
})
self.user = self.env['res.users'].create({
'name': 'Mark User',
'login': 'user',
'alias_name': 'mark',
'email': 'm.u@example.com',
'signature': '--\nMark',
'notify_email': 'always',
'groups_id': [(6, 0, [group_user.id])]
})
# create quotation with differend kinds of products (all possible combinations)
self.products = {
'prod_order': self.env.ref('product.product_product_43'),
'prod_del': self.env.ref('product.product_product_47'),
'serv_order': self.env.ref('product.product_product_0'),
'serv_del': self.env.ref('product.product_product_56'),
}
self.partner = self.env.ref('base.res_partner_1')
+124
View File
@@ -0,0 +1,124 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.exceptions import UserError, AccessError
from test_sale_common import TestSale
class TestSaleOrder(TestSale):
def test_sale_order(self):
""" Test the sale order flow (invoicing and quantity updates)
- Invoice repeatedly while varrying delivered quantities and check that invoice are always what we expect
"""
# DBO TODO: validate invoice and register payments
inv_obj = self.env['account.invoice']
so = self.env['sale.order'].create({
'partner_id': self.partner.id,
'partner_invoice_id': self.partner.id,
'partner_shipping_id': self.partner.id,
'order_line': [(0, 0, {'name': p.name, 'product_id': p.id, 'product_uom_qty': 2, 'product_uom': p.uom_id.id, 'price_unit': p.list_price}) for (_, p) in self.products.iteritems()],
'pricelist_id': self.env.ref('product.list0').id,
})
self.assertEqual(so.amount_total, sum([2 * p.list_price for (k, p) in self.products.iteritems()]), 'Sale: total amount is wrong')
# send quotation
so.force_quotation_send()
self.assertTrue(so.state == 'sent', 'Sale: state after sending is wrong')
# confirm quotation
so.action_confirm()
self.assertTrue(so.state == 'sale')
self.assertTrue(so.invoice_status == 'to invoice')
# create invoice: only 'invoice on order' products are invoiced
inv_id = so.action_invoice_create()
inv = inv_obj.browse(inv_id)
self.assertEqual(len(inv.invoice_line_ids), 2, 'Sale: invoice is missing lines')
self.assertEqual(inv.amount_total, sum([2 * p.list_price if p.invoice_policy == 'order' else 0 for (k, p) in self.products.iteritems()]), 'Sale: invoice total amount is wrong')
self.assertTrue(so.invoice_status == 'no', 'Sale: SO status after invoicing should be "nothing to invoice"')
self.assertTrue(len(so.invoice_ids) == 1, 'Sale: invoice is missing')
# deliver lines except 'time and material' then invoice again
for line in so.order_line:
line.qty_delivered = 2 if line.product_id.invoice_policy in ['order', 'delivery'] else 0
self.assertTrue(so.invoice_status == 'to invoice', 'Sale: SO status after delivery should be "to invoice"')
inv_id = so.action_invoice_create()
inv = inv_obj.browse(inv_id)
self.assertEqual(len(inv.invoice_line_ids), 2, 'Sale: second invoice is missing lines')
self.assertEqual(inv.amount_total, sum([2 * p.list_price if p.invoice_policy == 'delivery' else 0 for (k, p) in self.products.iteritems()]), 'Sale: second invoice total amount is wrong')
self.assertTrue(so.invoice_status == 'invoiced', 'Sale: SO status after invoicing everything should be "invoiced"')
self.assertTrue(len(so.invoice_ids) == 2, 'Sale: invoice is missing')
# go over the sold quantity
for line in so.order_line:
if line.product_id == self.products['serv_order']:
line.qty_delivered = 10
self.assertTrue(so.invoice_status == 'upselling', 'Sale: SO status after increasing delivered qty higher than ordered qty should be "upselling"')
# upsell and invoice
for line in so.order_line:
if line.product_id == self.products['serv_order']:
line.product_uom_qty = 10
inv_id = so.action_invoice_create()
inv = inv_obj.browse(inv_id)
self.assertEqual(len(inv.invoice_line_ids), 1, 'Sale: third invoice is missing lines')
self.assertEqual(inv.amount_total, 8 * self.products['serv_order'].list_price, 'Sale: second invoice total amount is wrong')
self.assertTrue(so.invoice_status == 'invoiced', 'Sale: SO status after invoicing everything (including the upsel) should be "invoiced"')
def test_unlink_cancel(self):
""" Test deleting and cancelling sale orders depending on their state and on the user's rights """
so = self.env['sale.order'].create({
'partner_id': self.partner.id,
'partner_invoice_id': self.partner.id,
'partner_shipping_id': self.partner.id,
'order_line': [(0, 0, {'name': p.name, 'product_id': p.id, 'product_uom_qty': 2, 'product_uom': p.uom_id.id, 'price_unit': p.list_price}) for (_, p) in self.products.iteritems()],
'pricelist_id': self.env.ref('product.list0').id,
})
# only quotations are deletable
with self.assertRaises(UserError):
so.action_confirm()
so.unlink()
so_copy = so.copy()
with self.assertRaises(AccessError):
so_copy.sudo(self.user).unlink()
self.assertTrue(so_copy.sudo(self.manager).unlink(), 'Sale: deleting a quotation should be possible')
# cancelling and setting to done, you should not be able to delete any SO ever
so.action_cancel()
self.assertTrue(so.state == 'cancel', 'Sale: cancelling SO should always be possible')
with self.assertRaises(UserError):
so.sudo(self.manager).unlink()
so.action_done()
self.assertTrue(so.state == 'done', 'Sale: SO not done')
def test_cost_invoicing(self):
""" Test confirming a vendor invoice to reinvoice cost on the so """
serv_cost = self.env.ref('product.product_product_1b')
prod_gap = self.env.ref('product.product_product_1')
so = self.env['sale.order'].create({
'partner_id': self.partner.id,
'partner_invoice_id': self.partner.id,
'partner_shipping_id': self.partner.id,
'order_line': [(0, 0, {'name': prod_gap.name, 'product_id': prod_gap.id, 'product_uom_qty': 2, 'product_uom': prod_gap.uom_id.id, 'price_unit': prod_gap.list_price})],
'pricelist_id': self.env.ref('product.list0').id,
})
so.action_confirm()
so._create_analytic_account()
inv_partner = self.env.ref('base.res_partner_2')
company = self.env.ref('base.main_company')
journal = self.env['account.journal'].create({'name': 'Purchase Journal - Test', 'code': 'STPJ', 'type': 'purchase', 'company_id': company.id})
account_payable = self.env['account.account'].create({'code': 'X1111', 'name': 'Sale - Test Payable Account', 'user_type_id': self.env.ref('account.data_account_type_payable').id, 'reconcile': True})
account_income = self.env['account.account'].create({'code': 'X1112', 'name': 'Sale - Test Account', 'user_type_id': self.env.ref('account.data_account_type_direct_costs').id})
invoice_vals = {
'name': '',
'type': 'in_invoice',
'partner_id': inv_partner.id,
'invoice_line_ids': [(0, 0, {'name': serv_cost.name, 'product_id': serv_cost.id, 'quantity': 2, 'uom_id': serv_cost.uom_id.id, 'price_unit': serv_cost.standard_price, 'account_analytic_id': so.project_id.id, 'account_id': account_income.id})],
'account_id': account_payable.id,
'journal_id': journal.id,
'currency_id': company.currency_id.id,
}
inv = self.env['account.invoice'].create(invoice_vals)
inv.signal_workflow('invoice_open')
sol = so.order_line.filtered(lambda l: l.product_id == serv_cost)
self.assertTrue(sol, 'Sale: cost invoicing does not add lines when confirming vendor invoice')
self.assertTrue(sol.price_unit == 160 and sol.qty_delivered == 2 and sol.product_uom_qty == sol.qty_invoiced == 0, 'Sale: line is wrong after confirming vendor invoice')
+5 -6
View File
@@ -20,7 +20,6 @@ class TestSale(TestMail):
account_obj = self.env['account.account']
# Usefull record id
group_id = IrModelData.xmlid_to_res_id('account.group_account_invoice') or False
product_id = IrModelData.xmlid_to_res_id('product.product_category_3') or False
company_id = IrModelData.xmlid_to_res_id('base.main_company') or False
# Usefull accounts
@@ -53,13 +52,13 @@ class TestSale(TestMail):
# In order to test I create sale order and confirmed it.
order = self.env['sale.order'].create({
'partner_id': partner.id,
'date_order': datetime.today()})
order_line = self.env['sale.order.line'].create({
'order_id': order.id,
'product_id': product_id})
'partner_invoice_id': partner.id,
'partner_shipping_id': partner.id,
'date_order': datetime.today(),
'pricelist_id': self.env.ref('product.list0').id})
assert order, "Sale order will not created."
context = {"active_model": 'sale.order', "active_ids": [order.id], "active_id": order.id}
order.with_context(context).action_button_confirm()
order.with_context(context).action_confirm()
# Now I create invoice.
payment = self.env['sale.advance.payment.inv'].create({'advance_payment_method': 'fixed', 'amount': 5})
invoice = payment.with_context(context).create_invoices()
+24 -22
View File
@@ -67,28 +67,30 @@
</tr>
</thead>
<tbody class="sale_tbody">
<tr t-foreach="doc.order_line" t-as="l">
<td>
<span t-field="l.name"/>
</td>
<td class="text-right">
<span t-field="l.product_uom_qty"/>
<span groups="product.group_uom" t-field="l.product_uom"/>
</td>
<td class="text-right">
<span t-field="l.price_unit"/>
</td>
<td t-if="display_discount" class="text-right" groups="sale.group_discount_per_so_line">
<span t-field="l.discount"/>
</td>
<td>
<span t-esc="', '.join(map(lambda x: x.name, l.tax_id))"/>
</td>
<td class="text-right">
<span t-field="l.price_subtotal"
t-field-options='{"widget": "monetary", "display_currency": "doc.pricelist_id.currency_id"}'/>
</td>
</tr>
<t t-foreach="doc.order_line" t-as="l">
<tr t-if="l.product_uom_qty">
<td>
<span t-field="l.name"/>
</td>
<td class="text-right">
<span t-field="l.product_uom_qty"/>
<span groups="product.group_uom" t-field="l.product_uom"/>
</td>
<td class="text-right">
<span t-field="l.price_unit"/>
</td>
<td t-if="display_discount" class="text-right" groups="sale.group_discount_per_so_line">
<span t-field="l.discount"/>
</td>
<td>
<span t-esc="', '.join(map(lambda x: x.name, l.tax_id))"/>
</td>
<td class="text-right">
<span t-field="l.price_subtotal"
t-field-options='{"widget": "monetary", "display_currency": "doc.pricelist_id.currency_id"}'/>
</td>
</tr>
</t>
</tbody>
</table>
-2
View File
@@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import sale_make_invoice
import sale_line_invoice
import sale_make_invoice_advance
-119
View File
@@ -1,119 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.osv import osv, fields
from openerp.tools.translate import _
from openerp import workflow
from openerp.exceptions import UserError
class sale_order_line_make_invoice(osv.osv_memory):
_name = "sale.order.line.make.invoice"
_description = "Sale OrderLine Make_invoice"
def _prepare_invoice(self, cr, uid, order, lines, context=None):
a = order.partner_id.property_account_receivable_id.id
if order.partner_id and order.partner_id.property_payment_term_id.id:
pay_term = order.partner_id.property_payment_term_id.id
else:
pay_term = False
return {
'name': order.client_order_ref or '',
'origin': order.name,
'type': 'out_invoice',
'reference': "P%dSO%d" % (order.partner_id.id, order.id),
'account_id': a,
'partner_id': order.partner_invoice_id.id,
'invoice_line_ids': [(6, 0, lines)],
'currency_id' : order.pricelist_id.currency_id.id,
'comment': order.note,
'payment_term_id': pay_term,
'fiscal_position_id': order.fiscal_position_id.id or order.partner_id.property_account_position_id.id,
'user_id': order.user_id and order.user_id.id or False,
'company_id': order.company_id and order.company_id.id or False,
'date_invoice': fields.date.today(),
'team_id': order.team_id.id,
}
def make_invoices(self, cr, uid, ids, context=None):
"""
To make invoices.
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param ids: the ID or list of IDs
@param context: A standard dictionary
@return: A dictionary which of fields with values.
"""
if context is None: context = {}
res = False
invoices = {}
#TODO: merge with sale.py/make_invoice
def make_invoice(order, lines):
"""
To make invoices.
@param order:
@param lines:
@return:
"""
inv = self._prepare_invoice(cr, uid, order, lines)
inv_id = self.pool.get('account.invoice').create(cr, uid, inv)
return inv_id
sales_order_line_obj = self.pool.get('sale.order.line')
sales_order_obj = self.pool.get('sale.order')
for line in sales_order_line_obj.browse(cr, uid, context.get('active_ids', []), context=context):
if (not line.invoiced) and (line.state not in ('draft', 'cancel')):
if not line.order_id in invoices:
invoices[line.order_id] = []
line_id = sales_order_line_obj.invoice_line_create(cr, uid, [line.id])
for lid in line_id:
invoices[line.order_id].append(lid)
for order, il in invoices.items():
res = make_invoice(order, il)
cr.execute('INSERT INTO sale_order_invoice_rel \
(order_id,invoice_id) values (%s,%s)', (order.id, res))
sales_order_obj.invalidate_cache(cr, uid, ['invoice_ids'], [order.id], context=context)
flag = True
sales_order_obj.message_post(cr, uid, [order.id], body=_("Invoice created"), context=context)
data_sale = sales_order_obj.browse(cr, uid, order.id, context=context)
for line in data_sale.order_line:
if not line.invoiced and line.state != 'cancel':
flag = False
break
if flag:
line.order_id.write({'state': 'progress'})
workflow.trg_validate(uid, 'sale.order', order.id, 'all_lines', cr)
if not invoices:
raise UserError(_('Invoice cannot be created for this Sales Order Line due to one of the following reasons:\n1.The state of this sales order line is either "draft" or "cancel"!\n2.The Sales Order Line is Invoiced!'))
if context.get('open_invoices', False):
return self.open_invoices(cr, uid, ids, res, context=context)
return {'type': 'ir.actions.act_window_close'}
def open_invoices(self, cr, uid, ids, invoice_ids, context=None):
""" open a view on one of the given invoice_ids """
ir_model_data = self.pool.get('ir.model.data')
form_res = ir_model_data.get_object_reference(cr, uid, 'account', 'invoice_form')
form_id = form_res and form_res[1] or False
tree_res = ir_model_data.get_object_reference(cr, uid, 'account', 'invoice_tree')
tree_id = tree_res and tree_res[1] or False
return {
'name': _('Invoice'),
'view_type': 'form',
'view_mode': 'form,tree',
'res_model': 'account.invoice',
'res_id': invoice_ids,
'view_id': False,
'views': [(form_id, 'form'), (tree_id, 'tree')],
'context': {'type': 'out_invoice'},
'type': 'ir.actions.act_window',
}
-42
View File
@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_sale_order_line_make_invoice" model="ir.ui.view">
<field name="name">Sales OrderLine Make Invoice</field>
<field name="model">sale.order.line.make.invoice</field>
<field name="arch" type="xml">
<form string="Create invoices">
<p class="oe_grey">
All items in these order lines will be invoiced. You can also invoice a percentage of the sales order
or a fixed price (for advances) directly from the sales order form if you prefer.
</p>
<footer>
<button name="make_invoices" string="Create &amp; View Invoice" type="object"
context="{'open_invoices': True}" class="oe_highlight"/>
<button name="make_invoices" string="Create Invoices" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_view_sale_order_line_make_invoice" model="ir.actions.act_window">
<field name="name">Create Invoice</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.order.line.make.invoice</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_sale_order_line_make_invoice"/>
<field name="target">new</field>
</record>
<record model="ir.values" id="sale_order_line_make_invoice">
<field name="model_id" ref="sale.model_sale_order_line" />
<field name="name">Make Invoices</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_view_sale_order_line_make_invoice'))" />
<field name="key">action</field>
<field name="model">sale.order.line</field>
</record>
</data>
</openerp>
-52
View File
@@ -1,52 +0,0 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp.exceptions import UserError
class sale_make_invoice(osv.osv_memory):
_name = "sale.make.invoice"
_description = "Sales Make Invoice"
_columns = {
'grouped': fields.boolean('Group the invoices', help='Check the box to group the invoices for the same customers'),
'invoice_date': fields.date('Invoice Date'),
}
_defaults = {
'grouped': False,
'invoice_date': fields.date.context_today,
}
def view_init(self, cr, uid, fields_list, context=None):
if context is None:
context = {}
record_id = context and context.get('active_id', False)
order = self.pool.get('sale.order').browse(cr, uid, record_id, context=context)
if order.state == 'draft':
raise UserError(_('You cannot create invoice when sales order is not confirmed.'))
return False
def make_invoices(self, cr, uid, ids, context=None):
order_obj = self.pool.get('sale.order')
mod_obj = self.pool.get('ir.model.data')
act_obj = self.pool.get('ir.actions.act_window')
newinv = []
if context is None:
context = {}
data = self.read(cr, uid, ids)[0]
for sale_order in order_obj.browse(cr, uid, context.get(('active_ids'), []), context=context):
if sale_order.state != 'manual':
raise UserError(_("You shouldn't manually invoice the following sale order %s") % (sale_order.name))
order_obj.action_invoice_create(cr, uid, context.get(('active_ids'), []), data['grouped'], date_invoice=data['invoice_date'])
orders = order_obj.browse(cr, uid, context.get(('active_ids'), []), context=context)
for o in orders:
for i in o.invoice_ids:
newinv.append(i.id)
# Dummy call to workflow, will not create another invoice but bind the new invoice to the subflow
order_obj.signal_workflow(cr, uid, [o.id for o in orders if o.order_policy == 'manual'], 'manual_invoice')
result = mod_obj.get_object_reference(cr, uid, 'account', 'action_invoice_tree1')
id = result and result[1] or False
result = act_obj.read(cr, uid, [id], context=context)[0]
result['domain'] = "[('id','in', [" + ','.join(map(str, newinv)) + "])]"
return result
-42
View File
@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_sale_order_make_invoice" model="ir.ui.view">
<field name="name">Create invoices</field>
<field name="model">sale.make.invoice</field>
<field name="arch" type="xml">
<form string="Create invoices">
<separator colspan="4" string="Do you really want to create the invoice(s)?" />
<group>
<field name="grouped"/>
<field name="invoice_date"/>
</group>
<footer>
<button name="make_invoices" string="Create Invoices" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_sale_order_make_invoice" model="ir.actions.act_window">
<field name="name">Make Invoices</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.make.invoice</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_sale_order_make_invoice"/>
<field name="target">new</field>
<field name="multi">True</field>
</record>
<record model="ir.values" id="sale_order_make_invoice">
<field name="model_id" ref="sale.model_sale_order" />
<field name="name">Make Invoices</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_sale_order_make_invoice'))" />
<field name="key">action</field>
<field name="model">sale.order</field>
</record>
</data>
</openerp>
+114 -176
View File
@@ -1,197 +1,135 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.osv import fields, osv
from openerp.tools.translate import _
import time
from openerp import api, fields, models, _
import openerp.addons.decimal_precision as dp
from openerp.exceptions import UserError
class sale_advance_payment_inv(osv.osv_memory):
class SaleAdvancePaymentInv(models.TransientModel):
_name = "sale.advance.payment.inv"
_description = "Sales Advance Payment Invoice"
_columns = {
'advance_payment_method':fields.selection(
[('all', 'Invoice the whole sales order'), ('percentage','Percentage'), ('fixed','Fixed price (deposit)'),
('lines', 'Some order lines')],
'What do you want to invoice?', required=True,
help="""Use Invoice the whole sale order to create the final invoice.\nUse Percentage to invoice a percentage of the total amount.\nUse Fixed Price to invoice a specific amount in advance.\nUse Some Order Lines to invoice a selection of the sales order lines."""),
'qtty': fields.float('Quantity', digits=(16, 2), required=True),
'product_id': fields.many2one('product.product', 'Advance Product',
domain=[('type', '=', 'service')],
help="Select a product of type service which is called 'Advance Product'.\nYou may have to create it and set it as a default value on this field."),
'amount': fields.float('Advance Amount', digits=0,
help="The amount to be invoiced in advance. \nTaxes are not taken into account for advance invoices."),
}
@api.model
def _count(self):
return len(self._context.get('active_ids', []))
def _get_advance_product(self, cr, uid, context=None):
@api.model
def _get_advance_payment_method(self):
if self._count() == 1:
sale_obj = self.env['sale.order']
order = sale_obj.browse(self._context.get('active_ids'))[0]
if all([line.product_id.invoice_policy == 'order' for line in order.order_line]):
return 'all'
return 'delivered'
@api.model
def _get_advance_product(self):
try:
product = self.pool.get('ir.model.data').get_object(cr, uid, 'sale', 'advance_product_0')
return self.env['ir.model.data'].xmlid_to_res_id('sale.advance_product_0', raise_if_not_found=True)
except ValueError:
# a ValueError is returned if the xml id given is not found in the table ir_model_data
return False
return product.id
_defaults = {
'advance_payment_method': 'all',
'qtty': 1.0,
'product_id': _get_advance_product,
}
advance_payment_method = fields.Selection([
('delivered', 'Ready to invoice'),
('all', 'Ready to invoice (with refunds)'),
('percentage', 'Deposit (percentage)'),
('fixed', 'Deposit (fixed amount)')
], string='What do you want to invoice?', default=_get_advance_payment_method, required=True)
product_id = fields.Many2one('product.product', string='Deposit Product', domain=[('type', '=', 'service')], default=_get_advance_product)
count = fields.Integer(default=_count, string='# of Orders')
amount = fields.Float('Deposit Amount', digits=dp.get_precision('Account'), help="The amount to be invoiced in advance, taxes excluded.")
def _translate_advance(self, cr, uid, percentage=False, context=None):
return _("Advance of %s %%") if percentage else _("Advance of %s %s")
@api.onchange('advance_payment_method')
def onchange_advance_payment_method(self):
if self.advance_payment_method == 'percentage':
return {'value': {'amount':0, 'product_id':False}}
return {}
def onchange_method(self, cr, uid, ids, advance_payment_method, product_id, context=None):
if advance_payment_method == 'percentage':
return {'value': {'amount':0, 'product_id':False }}
if product_id:
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
return {'value': {'amount': product.list_price}}
return {'value': {'amount': 0}}
@api.multi
def _create_invoice(self, order, so_line, amount):
inv_obj = self.env['account.invoice']
ir_property_obj = self.env['ir.property']
def _prepare_advance_invoice_vals(self, cr, uid, ids, context=None):
if context is None:
context = {}
sale_obj = self.pool.get('sale.order')
ir_property_obj = self.pool.get('ir.property')
fiscal_obj = self.pool.get('account.fiscal.position')
inv_line_obj = self.pool.get('account.invoice.line')
invoice_obj = self.pool.get('account.invoice')
wizard = self.browse(cr, uid, ids[0], context)
sale_ids = context.get('active_ids', [])
account_id = False
if self.product_id.id:
account_id = self.product_id.property_account_income_id.id
if not account_id:
prop = ir_property_obj.get('property_account_income_categ_id', 'product.category')
prop_id = prop and prop.id or False
account_id = order.fiscal_position_id.map_account(prop_id)
if not account_id:
raise UserError(
_('There is no income account defined for this product: "%s". You may have to install a chart of account from Accounting app, settings menu.') % \
(self.product_id.name,))
result = []
for sale in sale_obj.browse(cr, uid, sale_ids, context=context):
new_invoice = invoice_obj.new(cr, uid, {
'invoice_line_ids':[(0, 0, {'product_id': wizard.product_id.id})],
'partner_id': sale.partner_id.id,
'fiscal_position_id': sale.fiscal_position_id.id,
'type': 'out_invoice',
})
inv_line = new_invoice.invoice_line_ids[0]
inv_line.invoice_id = new_invoice #Little hack to in order to old <-> new api
inv_line._onchange_product_id()
if self.amount <= 0.00:
raise UserError(_('The value of Advance Amount must be positive.'))
if self.advance_payment_method == 'percentage':
amount = order.amount_untaxed * self.amount / 100
name = _("Advance of %s%%") % (self.amount,)
else:
amount = self.amount
name = _('Advance')
res = inv_line._convert_to_write(inv_line._cache)
invoice = inv_obj.create({
'name': order.client_order_ref or order.name,
'origin': order.name,
'type': 'out_invoice',
'reference': False,
'account_id': order.partner_id.property_account_receivable_id.id,
'partner_id': order.partner_invoice_id.id,
'invoice_line_ids': [(0, 0, {
'name': name,
'origin': order.name,
'account_id': account_id,
'price_unit': amount,
'quantity': 1.0,
'discount': 0.0,
'uom_id': self.product_id.uom_id.id,
'product_id': self.product_id.id,
'sale_line_ids': [(6, 0, [so_line.id])],
'invoice_line_tax_ids': [(6, 0, [x.id for x in self.product_id.taxes_id])],
'account_analytic_id': order.project_id.id or False,
})],
'currency_id': order.pricelist_id.currency_id.id,
'payment_term_id': order.payment_term_id.id,
'fiscal_position_id': order.fiscal_position_id.id or order.partner_id.property_account_position_id.id,
'team_id': order.team_id.id,
})
invoice.compute_taxes()
return invoice
# determine and check income account
if not wizard.product_id.id :
prop = ir_property_obj.get(cr, uid,
'property_account_income_categ_id', 'product.category', context=context)
prop_id = prop and prop.id or False
account_id = fiscal_obj.map_account(cr, uid, sale.fiscal_position_id or False, prop_id)
if not account_id:
raise UserError(
_('There is no income account defined as global property.'))
res['account_id'] = account_id
if not res.get('account_id'):
raise UserError(
_('There is no income account defined for this product: "%s" (id:%d).') % \
(wizard.product_id.name, wizard.product_id.id,))
@api.multi
def create_invoices(self):
sale_orders = self.env['sale.order'].browse(self._context.get('active_ids', []))
# determine invoice amount
if wizard.amount <= 0.00:
raise UserError(_('The value of Advance Amount must be positive.'))
if wizard.advance_payment_method == 'percentage':
inv_amount = sale.amount_untaxed * wizard.amount / 100
if not res.get('name'):
res['name'] = self._translate_advance(cr, uid, percentage=True, context=dict(context, lang=sale.partner_id.lang)) % (wizard.amount)
else:
inv_amount = wizard.amount
if not res.get('name'):
#TODO: should find a way to call formatLang() from rml_parse
symbol = sale.pricelist_id.currency_id.symbol
if sale.pricelist_id.currency_id.position == 'after':
symbol_order = (inv_amount, symbol)
else:
symbol_order = (symbol, inv_amount)
res['name'] = self._translate_advance(cr, uid, context=dict(context, lang=sale.partner_id.lang)) % symbol_order
# create the invoice
inv_line_values = {
'name': res.get('name'),
'origin': sale.name,
'account_id': res['account_id'],
'price_unit': inv_amount,
'quantity': wizard.qtty or 1.0,
'discount': False,
'uos_id': res.get('uos_id', False),
'product_id': wizard.product_id.id,
'invoice_line_tax_ids': res.get('invoice_line_tax_ids'),
'account_analytic_id': sale.project_id.id or False,
}
inv_values = {
'name': sale.client_order_ref or sale.name,
'origin': sale.name,
'type': 'out_invoice',
'reference': False,
'account_id': sale.partner_id.property_account_receivable_id.id,
'partner_id': sale.partner_invoice_id.id,
'invoice_line_ids': [(0, 0, inv_line_values)],
'currency_id': sale.pricelist_id.currency_id.id,
'comment': sale.note,
'payment_term_id': sale.payment_term_id.id,
'fiscal_position_id': sale.fiscal_position_id.id or sale.partner_id.property_account_position_id.id,
'team_id': sale.team_id.id,
}
result.append((sale.id, inv_values))
return result
def _create_invoices(self, cr, uid, inv_values, sale_id, context=None):
inv_obj = self.pool.get('account.invoice')
sale_obj = self.pool.get('sale.order')
inv_id = inv_obj.create(cr, uid, inv_values, context=context)
inv_obj.compute_taxes(cr, uid, [inv_id], context=context)
# add the invoice to the sales order's invoices
sale_obj.write(cr, uid, sale_id, {'invoice_ids': [(4, inv_id)]}, context=context)
return inv_id
def create_invoices(self, cr, uid, ids, context=None):
""" create invoices for the active sales orders """
sale_obj = self.pool.get('sale.order')
act_window = self.pool.get('ir.actions.act_window')
wizard = self.browse(cr, uid, ids[0], context)
sale_ids = context.get('active_ids', [])
if wizard.advance_payment_method == 'all':
# create the final invoices of the active sales orders
res = sale_obj.manual_invoice(cr, uid, sale_ids, context)
if context.get('open_invoices', False):
return res
return {'type': 'ir.actions.act_window_close'}
if wizard.advance_payment_method == 'lines':
# open the list view of sales order lines to invoice
res = act_window.for_xml_id(cr, uid, 'sale', 'action_order_line_tree2', context)
res['context'] = {
'search_default_uninvoiced': 1
}
res['domain'] = [('order_id','=', sale_ids and sale_ids[0] or False)]
return res
assert wizard.advance_payment_method in ('fixed', 'percentage')
inv_ids = []
for sale_id, inv_values in self._prepare_advance_invoice_vals(cr, uid, ids, context=context):
inv_ids.append(self._create_invoices(cr, uid, inv_values, sale_id, context=context))
if context.get('open_invoices', False):
return self.open_invoices( cr, uid, ids, inv_ids, context=context)
if self.advance_payment_method == 'delivered':
sale_orders.action_invoice_create()
elif self.advance_payment_method == 'all':
sale_orders.action_invoice_create(final=True)
else:
sale_line_obj = self.env['sale.order.line']
for order in sale_orders:
if self.advance_payment_method == 'percentage':
amount = order.amount_untaxed * self.amount / 100
else:
amount = self.amount
if self.product_id.invoice_policy != 'order':
raise UserError(_('The product used to invoice a deposit should have an invoice policy set to "Ordered quantities". Please update your deposit product to be able to create a deposit invoice.'))
if self.product_id.type != 'service':
raise UserError(_("The product used to invoice an deposit should be of type 'Service'. Please use another product or update this product."))
so_line = sale_line_obj.create({
'name': _('Advance: %s') % (time.strftime('%m %Y'),),
'price_unit': amount,
'product_uom_qty': 0.0,
'order_id': order.id,
'discount': 0.0,
'product_uom': self.product_id.uom_id.id,
'product_id': self.product_id.id,
'tax_id': self.product_id.taxes_id,
})
self._create_invoice(order, so_line, amount)
if self._context.get('open_invoices', False):
return sale_orders.action_view_invoice()
return {'type': 'ir.actions.act_window_close'}
def open_invoices(self, cr, uid, ids, invoice_ids, context=None):
""" open a view on one of the given invoice_ids """
ir_model_data = self.pool.get('ir.model.data')
form_res = ir_model_data.get_object_reference(cr, uid, 'account', 'invoice_form')
form_id = form_res and form_res[1] or False
tree_res = ir_model_data.get_object_reference(cr, uid, 'account', 'invoice_tree')
tree_id = tree_res and tree_res[1] or False
return {
'name': _('Advance Invoice'),
'view_type': 'form',
'view_mode': 'form,tree',
'res_model': 'account.invoice',
'res_id': invoice_ids[0],
'view_id': False,
'views': [(form_id, 'form'), (tree_id, 'tree')],
'context': "{'type': 'out_invoice'}",
'type': 'ir.actions.act_window',
}
@@ -2,23 +2,21 @@
<openerp>
<data>
<record id="view_sale_advance_payment_inv" model="ir.ui.view">
<field name="name">Invoice Order</field>
<field name="name">Invoice Orders</field>
<field name="model">sale.advance.payment.inv</field>
<field name="arch" type="xml">
<form string="Invoice Sales Order">
<p class="oe_grey">
Select how you want to invoice this order. This
will create a draft invoice that can be modified
before validation.
Invoices will be created in draft so that you can update
them before validation.
</p>
<group>
<field name="count" invisible="[('count','=',1)]" readonly="True"/>
<field name="advance_payment_method" class="oe_inline" widget="radio"
on_change="onchange_method(advance_payment_method, product_id)"/>
<field name="qtty" invisible="1"/>
attrs="{'invisible': [('count','&gt;',1)]}"/>
<field name="product_id"
on_change="onchange_method(advance_payment_method, product_id)"
context="{'search_default_services': 1}"
attrs="{'invisible': [('advance_payment_method','!=','fixed')]}"/>
context="{'search_default_services': 1, 'default_type': 'service', 'default_invoice_policy': 'order'}" class="oe_inline"
attrs="{'invisible': [('advance_payment_method','not in', ('fixed','percentage'))]}"/>
<label for="amount" attrs="{'invisible': [('advance_payment_method', 'not in', ('fixed','percentage'))]}"/>
<div attrs="{'invisible': [('advance_payment_method', 'not in', ('fixed','percentage'))]}">
<field name="amount"
@@ -27,19 +25,12 @@
attrs="{'invisible': [('advance_payment_method', '!=', 'percentage')]}" class="oe_inline"/>
</div>
</group>
<div>
<b><label string="After clicking 'Show Lines to Invoice', select lines to invoice and create the invoice from the 'More' dropdown menu." attrs="{'invisible': [('advance_payment_method', '!=', 'lines')]}"/></b>
</div>
<footer>
<button name="create_invoices" string="Create and View Invoice" type="object"
context="{'open_invoices': True}" class="btn-primary"
attrs="{'invisible': [('advance_payment_method', '=', 'lines')]}"/>
<button name="create_invoices" string="Create Invoice" type="object"
class="btn-primary"
attrs="{'invisible': [('advance_payment_method', '=', 'lines')]}"/>
<button name="create_invoices" string="Show Lines to Invoice" type="object"
class="btn-primary"
attrs="{'invisible': [('advance_payment_method', '!=', 'lines')]}"/>
<button name="create_invoices" string="Create and View Invoices" type="object"
context="{'open_invoices': True}" class="btn-primary"/>
<button name="create_invoices" string="Create Invoices" type="object"
class="btn-primary"/>
or
<button string="Cancel" class="btn-default" special="cancel"/>
</footer>
</form>
@@ -54,5 +45,16 @@
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!-- TODO: check if we need this -->
<record model="ir.values" id="sale_order_line_make_invoice">
<field name="model_id" ref="sale.model_sale_order_line" />
<field name="name">Invoice Orders</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_view_sale_advance_payment_inv'))" />
<field name="key">action</field>
<field name="model">sale.order</field>
</record>
</data>
</openerp>