Skip to content
Snippets Groups Projects
Commit e57ac164 authored by Nicolas Martinelli's avatar Nicolas Martinelli
Browse files

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

Major changes:
- No invoicing anymore
- Migration to new api

Reason: complete rewrite of the Sale module.

Responsible: fp, dbo, nim
parent de423ba1
No related branches found
No related tags found
No related merge requests found
Showing
with 264 additions and 1220 deletions
......@@ -31,22 +31,11 @@ You can choose flexible invoicing methods:
'security/ir.model.access.csv',
'company_view.xml',
'sale_stock_view.xml',
'sale_stock_workflow.xml',
'stock_view.xml',
'res_config_view.xml',
'report/sale_report_view.xml',
'account_invoice_view.xml',
],
'demo': ['sale_stock_demo.xml'],
'test': [
'../account/test/account_minimal_test.xml',
'test/sale_stock_users.yml',
'test/cancel_order_sale_stock.yml',
'test/picking_order_policy.yml',
'test/prepaid_order_policy.yml',
'test/sale_order_onchange.yml',
'test/sale_order_canceled_line.yml',
],
'installable': True,
'auto_install': True,
}
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_invoice_form_inherit" model="ir.ui.view">
<record id="invoice_form_inherit_sale_stock" model="ir.ui.view">
<field name="name">account.invoice.form.sale.stock</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
......@@ -13,7 +13,7 @@
</field>
</record>
<template id="report_invoice_incoterm" inherit_id="account.report_invoice_document">
<template id="report_invoice_document_inherit_sale_stock" inherit_id="account.report_invoice_document">
<xpath expr="//div[@name='reference']" position="after">
<div class="col-xs-2" t-if="o.incoterms_id" groups="sale.group_display_incoterm">
<strong>Incoterms:</strong>
......
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.osv import fields, osv
from openerp import fields, models
class company(osv.osv):
class company(models.Model):
_inherit = 'res.company'
_columns = {
'security_lead': fields.float(
'Sales Safety Days', required=True,
help="Margin of error for dates promised to customers. "\
"Products will be scheduled for procurement and delivery "\
"that many days earlier than the actual promised date, to "\
"cope with unexpected delays in the supply chain."),
}
_defaults = {
'security_lead': 0.0,
}
security_lead = fields.Float('Sales Safety Days', required=True, default = 0.0,
help="Margin of error for dates promised to customers. "\
"Products will be scheduled for procurement and delivery "\
"that many days earlier than the actual promised date, to "\
"cope with unexpected delays in the supply chain.")
<?xml version="1.0" ?>
<openerp>
<data>
<record id="mrp_company" model="ir.ui.view">
<record id="view_company_form_inherit_sale_stock" model="ir.ui.view">
<field name="name">res.company.mrp.config</field>
<field name="model">res.company</field>
<field name="priority">24</field>
......
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.osv import fields, osv
from openerp import tools
class sale_report(osv.osv):
from openerp import fields, models
class SaleReport(models.Model):
_inherit = "sale.report"
_columns = {
'shipped': fields.boolean('Shipped', readonly=True),
'shipped_qty_1': fields.integer('# of Shipped Lines', readonly=True),
'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse',readonly=True),
'state': fields.selection([
('draft', 'Draft Quotation'),
('sent', 'Quotation Sent'),
('waiting_date', 'Waiting Schedule'),
('manual', 'Sale to Invoice'),
('progress', 'Sale Order'),
('shipping_except', 'Shipping Exception'),
('invoice_except', 'Invoice Exception'),
('done', 'Done'),
('cancel', 'Cancelled')
], 'Order Status', readonly=True),
}
warehouse_id = fields.Many2one('stock.warehouse', 'Warehouse', readonly=True)
def _select(self):
return super(sale_report, self)._select() + ", s.warehouse_id as warehouse_id, s.shipped, s.shipped::integer as shipped_qty_1"
return super(SaleReport, self)._select() + ", s.warehouse_id as warehouse_id"
def _group_by(self):
return super(sale_report, self)._group_by() + ", s.warehouse_id, s.shipped"
return super(SaleReport, self)._group_by() + ", s.warehouse_id"
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Filters too specific to propose directly to the user
<record id="view_order_product_search_sale_stock_inherit" model="ir.ui.view">
<field name="name">sale.report.search.sale.stock</field>
<field name="model">sale.report</field>
<field name="inherit_id" ref="sale.view_order_product_search"/>
<field name="arch" type="xml">
<filter name="Sales" position="after">
<separator/>
<filter string="Picked" domain="[('shipped','=',True)]"/>
</filter>
<xpath expr="//group/filter[@name='status']" position="after">
<filter string="Warehouse" context="{'group_by':'warehouse_id'}"/>
</xpath>
</field>
</record>
-->
</data>
</openerp>
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import openerp
from openerp import SUPERUSER_ID
from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp import api, fields, models, _
from openerp.exceptions import AccessError
class sale_configuration(osv.osv_memory):
class SaleConfiguration(models.TransientModel):
_inherit = 'sale.config.settings'
_columns = {
'default_order_policy': fields.selection([
('manual', 'Invoice based on sales order'),
('picking', 'Invoice based on delivery orders')],
'Invoicing Method', default_model='sale.order'),
'module_delivery': fields.selection([
(0, 'No shipping costs on sales orders'),
(1, 'Allow adding shipping costs')
], "Shipping"),
'default_picking_policy' : fields.selection([
(0, 'Ship products when some are available, and allow back orders'),
(1, 'Ship all products at once, without back orders')
], "Default Shipping Policy"),
'group_mrp_properties': fields.selection([
(0, "Don't use manufacturing properties (recommended as its easier)"),
(1, 'Allow setting manufacturing order properties per order line (avanced)')
], "Properties on SO Lines",
implied_group='sale.group_mrp_properties',
help="Allows you to tag sales order lines with properties."),
'group_route_so_lines': fields.selection([
(0, 'No order specific routes like MTO or drop shipping'),
(1, 'Choose specific routes on sales order lines (advanced)')
], "Order Routing",
implied_group='sale_stock.group_route_so_lines'),
}
_defaults = {
'default_order_policy': 'manual',
}
def get_default_sale_config(self, cr, uid, ids, context=None):
ir_values = self.pool.get('ir.values')
default_picking_policy = ir_values.get_default(cr, uid, 'sale.order', 'picking_policy')
module_delivery = fields.Selection([
(0, 'No shipping costs on sales orders'),
(1, 'Allow adding shipping costs')
], "Shipping")
default_picking_policy = fields.Selection([
(0, 'Ship products when some are available, and allow back orders'),
(1, 'Ship all products at once, without back orders')
], "Default Shipping Policy")
group_mrp_properties = fields.Selection([
(0, "Don't use manufacturing properties (recommended as its easier)"),
(1, 'Allow setting manufacturing order properties per order line (avanced)')
], "Properties on SO Lines",
implied_group='sale.group_mrp_properties',
help="Allows you to tag sales order lines with properties.")
group_route_so_lines = fields.Selection([
(0, 'No order specific routes like MTO or drop shipping'),
(1, 'Choose specific routes on sales order lines (advanced)')
], "Order Routing",
implied_group='sale_stock.group_route_so_lines')
@api.multi
def get_default_sale_config(self):
default_picking_policy = self.env['ir.values'].get_default('sale.order', 'picking_policy')
return {
'default_picking_policy': (default_picking_policy == 'one') and 1 or 0,
'default_picking_policy': 1 if default_picking_policy == 'one' else 0,
}
def set_sale_defaults(self, cr, uid, ids, context=None):
if not self.pool['res.users']._is_admin(cr, uid, [uid]):
raise openerp.exceptions.AccessError(_("Only administrators can change the settings"))
ir_values = self.pool.get('ir.values')
wizard = self.browse(cr, uid, ids)[0]
@api.multi
def set_sale_defaults(self):
self.ensure_one()
if not self.env.user._is_admin():
raise AccessError(_("Only administrators can change the settings"))
default_picking_policy = 'one' if wizard.default_picking_policy else 'direct'
ir_values.set_default(cr, SUPERUSER_ID, 'sale.order', 'picking_policy', default_picking_policy)
res = super(sale_configuration, self).set_sale_defaults(cr, uid, ids, context)
default_picking_policy = 'one' if self.default_picking_policy else 'direct'
self.env['ir.values'].sudo().set_default('sale.order', 'picking_policy', default_picking_policy)
res = super(SaleConfiguration, self).set_sale_defaults()
return res
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_sales_config_sale_stock" model="ir.ui.view">
<record id="view_sales_config_inherit_sale_stock" model="ir.ui.view">
<field name="name">sale settings</field>
<field name="model">sale.config.settings</field>
<field name="inherit_id" ref="sale.view_sales_config"/>
......@@ -12,7 +12,6 @@
</group>
</xpath>
<xpath expr="//group[@id='sale']" position="inside">
<field name="default_order_policy" widget="radio"/>
<field name="group_route_so_lines" widget="radio"/>
<field name="group_mrp_properties" widget="radio" groups="base.group_no_one"/>
</xpath>
......
This diff is collapsed.
......@@ -4,7 +4,6 @@
<record id="sale.sale_order_1" model="sale.order">
<field name="warehouse_id" ref="stock.warehouse0"/>
<field name="order_policy">prepaid</field>
</record>
<record id="sale.sale_order_2" model="sale.order">
......@@ -17,23 +16,15 @@
<record id="sale.sale_order_5" model="sale.order">
<field name="warehouse_id" ref="stock.warehouse0"/>
<field name="order_policy">picking</field>
</record>
<record id="sale.sale_order_6" model="sale.order">
<field name="warehouse_id" ref="stock.warehouse0"/>
<field name="order_policy">picking</field>
</record>
<record id="sale.sale_order_8" model="sale.order">
<field name="warehouse_id" ref="stock.warehouse0"/>
</record>
<!-- Confirm some Sale Orders-->
<workflow action="order_confirm" model="sale.order" ref="sale.sale_order_5"/>
<!-- Run all schedulers -->
<function model="procurement.order" name="run_scheduler"/>
</data>
</openerp>
......@@ -6,7 +6,6 @@
if account_id:
vals = {
'warehouse_id': ref('stock.warehouse0'),
'order_policy': 'prepaid',
}
self._update(cr, uid, 'sale.order', 'sale', vals, 'sale_order_4')
......
......@@ -2,16 +2,12 @@
<openerp>
<data>
<record id="view_order_form_inherit" model="ir.ui.view">
<record id="view_order_form_inherit_sale_stock" model="ir.ui.view">
<field name="name">sale.order.form.sale.stock</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="//button[@name='invoice_corrected']" position="after">
<button name="ship_recreate" states="shipping_except" string="Recreate Delivery Order"/>
<button name="ship_corrected" states="shipping_except" string="Ignore Exception"/>
</xpath>
<xpath expr="//button[@name='action_view_invoice']" position="before">
<field name="picking_ids" invisible="1"/>
<button type="object"
......@@ -19,140 +15,31 @@
class="oe_stat_button"
icon="fa-truck"
attrs="{'invisible': [('delivery_count', '=', 0)]}" groups="base.group_user">
<field name="delivery_count" widget="statinfo" string="Transfers" help="Delivery Orders"/>
<field name="delivery_count" widget="statinfo" string="Delivery"/>
</button>
</xpath>
<xpath expr="//button[@name='action_cancel']" position="after">
<button name="ship_cancel" states="shipping_except" string="Cancel Order"/>
</xpath>
<field name="state" position="attributes">
<attribute name="statusbar_colors" t-translate="off">{"shipping_except":"red","invoice_except":"red","waiting_date":"blue"}</attribute>
</field>
<field name="company_id" position="replace">
<field name="company_id" readonly="True"/>
</field>
<xpath expr="//group[@name='sales_person']" position="before">
<group string="Shipping Information" name="sale_shipping">
<field name="warehouse_id" on_change="onchange_warehouse_id(warehouse_id)" options="{'no_create': True}" groups="stock.group_locations"/>
<field name="warehouse_id" options="{'no_create': True}" groups="stock.group_locations"/>
<field name="incoterm" widget="selection" groups="base.group_user"/>
<field name="picking_policy" required="True"/>
</group>
</xpath>
<xpath expr="//field[@name='order_line']/form//field[@name='product_id']" position="attributes">
<!-- no product_uos to force reset of product_uom, product_uos and product_uos_qty in porduct_id_change -->
<attribute name="on_change">product_id_change_with_wh(
parent.pricelist_id, product_id, product_uom_qty, False, product_uos_qty, False, name,
parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position_id,
False, parent.warehouse_id, context)
</attribute>
<attribute name="context">{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':False}</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/tree//field[@name='product_id']" position="attributes">
<attribute name="on_change">product_id_change_with_wh(
parent.pricelist_id, product_id, product_uom_qty, False, product_uos_qty, False, name,
parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position_id,
False, parent.warehouse_id, context)
</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/form//field[@name='product_uos_qty']" position="attributes">
<!-- keep product_uos to force update of product_uom and product_uom_qty in porduct_id_change -->
<attribute name="on_change">product_id_change_with_wh(
parent.pricelist_id, product_id, product_uom_qty, False, product_uos_qty, product_uos, name,
parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position_id,
False, parent.warehouse_id, context)
</attribute>
<xpath expr="//page/field[@name='order_line']/form/group/group/field[@name='tax_id']" position="before">
<field name="product_tmpl_id" invisible="1"/>
<field name="product_packaging" context="{'default_product_tmpl_id': product_tmpl_id, 'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}" domain="[('product_tmpl_id','=',product_tmpl_id)]" groups="product.group_stock_packaging" />
</xpath>
<xpath expr="//field[@name='order_line']/form//field[@name='product_uom_qty']" position="attributes">
<attribute name="on_change">product_id_change_with_wh(
parent.pricelist_id, product_id, product_uom_qty, product_uom, product_uos_qty, False, name,
parent.partner_id, False, False, parent.date_order, product_packaging, parent.fiscal_position_id,
True, parent.warehouse_id, context)
</attribute>
<xpath expr="//field[@name='order_line']/form/group/group/field[@name='price_unit']" position="before">
<field name="route_id" groups="sale_stock.group_route_so_lines"/>
</xpath>
<xpath expr="//group[@name='technical']" position="inside">
<field name="shipped" groups="base.group_no_one"/>
</xpath>
<xpath expr="//page/field[@name='order_line']/form/group/group/field[@name='tax_id']" position="after">
<label for="delay"/>
<div>
<field name="delay" class="oe_inline"/> days
</div>
</xpath>
<xpath expr="//page/field[@name='order_line']/form/group/group/field[@name='tax_id']" position="before">
<field name="product_tmpl_id" invisible="1"/>
<field name="product_packaging" context="{'default_product_tmpl_id': product_tmpl_id, 'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}" on_change="product_packaging_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, parent.partner_id, product_packaging, True, context)" domain="[('product_tmpl_id','=',product_tmpl_id)]" groups="product.group_stock_packaging" />
</xpath>
<xpath expr="//page/field[@name='order_line']/tree/field[@name='sequence']" position="after">
<field name="delay" invisible="1"/>
</xpath>
<xpath expr="//page/field[@name='order_line']/tree/field[@name='th_weight']" position="after">
<field name="product_packaging" invisible="1"/>
</xpath>
<xpath expr="//group[@name='sale_pay']" position="inside">
<field name="order_policy"/>
</xpath>
<xpath expr="//field[@name='order_line']/form/group/group/field[@name='price_unit']" position="before">
<xpath expr="//field[@name='order_line']/tree/field[@name='price_unit']" position="before">
<field name="route_id" groups="sale_stock.group_route_so_lines"/>
</xpath>
<xpath expr="//field[@name='order_line']/tree/field[@name='price_unit']" position="before">
<field name="route_id" groups="sale_stock.group_route_so_lines"/>
</xpath>
</xpath>
</data>
</field>
</record>
<record id="view_res_partner_tree_type" model="ir.ui.view">
<field name="name">res.partner.tree.inherit.type</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_tree"/>
<field name="arch" type="xml">
<field name="parent_id" position="after">
<field name="type" invisible="context.get('hide_type', 1)"/>
</field>
</field>
</record>
<!-- On the customer/supplier form if "Allow a different address for
delivery and invoicing" is set add "Contact Details" in the more menu
showing the list of contact with their types -->
<act_window
id="res_partner_rule_children"
name="Contact Details"
context="{'default_parent_id': active_id, 'hide_type': 0}"
domain="[('parent_id','=',active_id)]"
res_model="res.partner"
src_model="res.partner"
view_mode="tree,form,kanban"
view_type="form"
groups="sale.group_delivery_invoice_address"
/>
<record id="view_picking_internal_search_inherit" model="ir.ui.view">
<field name="name">stock.picking.search.inherit</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_internal_search"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="before">
<filter string="To Invoice" name="to_invoice" domain="[('invoice_state', '=', '2binvoiced')]"/>
</xpath>
</field>
</record>
<record id="view_order_form_inherit2" model="ir.ui.view">
<field name="name">sale.order.line.form.sale.stock.location</field>
<field name="model">sale.order.line</field>
<field name="inherit_id" ref="sale.view_order_line_form2"/>
<field name="arch" type="xml">
<data>
<xpath expr="//field[@name='price_unit']" position="before">
<field name="route_id" groups="sale_stock.group_route_so_lines" />
</xpath>
</data>
</field>
</record>
<record id="view_order_line_tree_inherit" model="ir.ui.view">
<record id="view_order_line_tree_inherit_sale_stock" model="ir.ui.view">
<field name="name">sale.order.line.tree.sale.stock.location</field>
<field name="inherit_id" ref="sale.view_order_line_tree"/>
<field name="model">sale.order.line</field>
......@@ -163,7 +50,7 @@
</field>
</record>
<template id="report_sale_order_incoterm" inherit_id="sale.report_saleorder_document">
<template id="report_saleorder_document_inherit_sale_stock" inherit_id="sale.report_saleorder_document">
<xpath expr="//div[@name='payment_term']" position="after">
<div class="col-xs-3" t-if="doc.incoterm" groups="sale.group_display_incoterm">
<strong>Incoterms:</strong>
......
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
</data>
</openerp>
......@@ -3,7 +3,7 @@
<data>
<!-- Add menu: Billing - Deliveries to invoice -->
<record id="outgoing_picking_list_to_invoice" model="ir.actions.act_window">
<record id="stock_picking_action_outgoing_picking_list_to_invoice" model="ir.actions.act_window">
<field name="name">Deliveries to Invoice</field>
<field name="res_model">stock.picking</field>
<field name="type">ir.actions.act_window</field>
......@@ -18,9 +18,9 @@
groups="base.group_sale_salesman"
parent="base.menu_base_partner" sequence="5" />
<menuitem id="base.menu_invoiced" name="Invoicing" parent="base.menu_aftersale" sequence="1"/>
<menuitem action="outgoing_picking_list_to_invoice" id="menu_action_picking_list_to_invoice" parent="base.menu_invoiced" sequence="20"/>
<menuitem action="stock_picking_action_outgoing_picking_list_to_invoice" id="menu_action_picking_list_to_invoice" parent="base.menu_invoiced" sequence="20"/>
<record id="stock_location_route_form_view_inherit" model="ir.ui.view">
<record id="stock_location_route_form_view_inherit_sale_stock" model="ir.ui.view">
<field name="name">stock.location.route.form</field>
<field name="inherit_id" ref="stock.stock_location_route_form_view"/>
<field name="model">stock.location.route</field>
......
-
In order to test the cancel sale order with that user which have salesman rights.
First I confirm order.
-
!context
uid: 'res_sale_stock_salesman'
-
!workflow {model: sale.order, action: order_confirm, ref: sale.sale_order_8}
-
I do a partial delivery order as a stock user.
-
!context
uid: 'res_stock_user'
-
!python {model: stock.picking}: |
domain = [('origin','=','Test/001')]
picks = self.search(cr, uid, domain, context=context)
pick = self.browse(cr, uid, picks[-1], context=context)
self.pool.get('stock.pack.operation').create(cr, uid, {
'picking_id': pick.id,
'product_id': ref('product.product_product_27'),
'product_uom_id': ref('product.product_uom_unit'),
'product_qty': 1,
'location_id': pick.location_id.id,
'location_dest_id': pick.location_dest_id.id,
})
pick.do_transfer()
-
I test that I have two pickings, one done and one backorder to do
-
!python {model: stock.picking}: |
picks = self.search(cr, uid, [('origin','=','Test/001')])
assert len(picks)>1, 'Only one picking, partial picking may have failed!'
picks = self.search(cr, uid, [('origin','=','Test/001'), ('state','=','done')])
assert len(picks)==1, 'You should have one delivery order which is done!'
picks = self.search(cr, uid, [('origin','=','Test/001'), ('backorder_id','=',picks[0])])
assert len(picks)==1, 'You should have one backorder to process!'
-
I cancel the backorder
-
!python {model: stock.picking}: |
picks = self.search(cr, uid, [('origin','=','Test/001'),('backorder_id','<>',False)])
self.action_cancel(cr, uid, picks)
-
I run the scheduler.
-
!python {model: procurement.order}: |
self.run_scheduler(cr, uid)
-
Salesman can also check order therefore test with that user which have salesman rights,
-
!context
uid: 'res_sale_stock_salesman'
-
I check order status in "Ship Exception".
-
!assert {model: sale.order, id: sale.sale_order_8, string: Sale order should be in shipping exception}:
- state == "shipping_except"
-
Now I regenerate shipment.
-
!workflow {model: sale.order, action: ship_recreate, ref: sale.sale_order_8}
-
I check state of order in 'To Invoice'.
-
!assert {model: sale.order, id: sale.sale_order_8, string: Sale order should be In Progress state}:
- state == 'manual'
-
I make invoice for order.
-
!workflow {model: sale.order, action: manual_invoice, ref: sale.sale_order_8}
-
To cancel the sale order from Invoice Exception, I have to cancel the invoice of sale order.
-
!python {model: sale.order}: |
invoice_ids = self.browse(cr, uid, ref("sale.sale_order_8")).invoice_ids
first_invoice_id = invoice_ids[0]
self.pool.get('account.invoice').signal_workflow(cr, uid, [first_invoice_id.id], 'invoice_cancel')
-
I check order status in "Invoice Exception" and related invoice is in cancel state.
-
!assert {model: sale.order, id: sale.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"
-
Then I click on the Ignore Exception button.
-
!workflow {model: sale.order, action: invoice_corrected, ref: sale.sale_order_8}
-
I check state of order in 'In Progress'.
-
!assert {model: sale.order, id: sale.sale_order_8, string: Sale order should be In progress state}:
- state == 'progress'
-
In order to test process of the Sale Order with access rights of saleman,
-
!context
uid: 'res_sale_stock_salesman'
-
Create a new SO to be sure we don't have one with product that can explode in mrp
-
!record {model: sale.order, id: sale_order_service}:
partner_id: base.res_partner_18
partner_invoice_id: base.res_partner_18
partner_shipping_id: base.res_partner_18
user_id: base.user_root
pricelist_id: product.list0
warehouse_id: stock.warehouse0
order_policy: picking
-
Add SO line with service type product in SO to check flow which contain service type product in SO(BUG#1167330).
-
!record {model: sale.order.line, id: sale_order_1}:
name: 'On Site Assistance'
product_id: product.product_product_2
product_uom_qty: 1.0
product_uom: 1
price_unit: 150.0
order_id: sale_order_service
-
Add a second SO line with a normal product
-
!record {model: sale.order.line, id: sale_order_2}:
name: 'Mouse Optical'
product_id: product.product_product_10
product_uom_qty: 1.0
product_uom: 1
price_unit: 150.0
order_id: sale_order_service
-
First I check the total amount of the Quotation before Approved.
-
!python {model: sale.order}: |
from openerp.tools import float_compare
so = self.browse(cr, uid, ref('sale_order_service'))
float_compare(sum([l.price_subtotal for l in so.order_line]), so.amount_untaxed, precision_digits=2) == 0, "The amount of the Quotation is not correctly computed"
-
I set an explicit invoicing partner that is different from the main SO Customer
-
!python {model: sale.order}: |
order = self.browse(cr, uid, ref("sale_order_service"))
order.write({'partner_invoice_id': ref('base.res_partner_address_30')})
-
I confirm the quotation with Invoice based on deliveries policy.
-
!workflow {model: sale.order, action: order_confirm, ref: sale_order_service}
-
I check that invoice should not created before dispatch delivery.
-
!python {model: sale.order}: |
order = self.pool.get('sale.order').browse(cr, uid, ref("sale_order_service"))
assert order.state == 'progress', 'Order should be in inprogress.'
assert len(order.invoice_ids) == False, "Invoice should not created."
-
I check the details of procurement after confirmed quotation.
-
!python {model: sale.order}: |
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
order = self.browse(cr, uid, ref("sale_order_service"))
for order_line in order.order_line:
if order_line.product_id.type == 'product':
procurement = order_line.procurement_ids[0]
date_planned = datetime.strptime(order.date_order, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta(days=order_line.delay or 0.0)
date_planned = (date_planned - timedelta(days=order.company_id.security_lead)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
assert procurement.date_planned == date_planned, "Scheduled date is not correspond."
assert procurement.product_id.id == order_line.product_id.id, "Product is not correspond."
assert procurement.product_qty == order_line.product_uom_qty, "Qty is not correspond."
assert procurement.product_uom.id == order_line.product_uom.id, "UOM is not correspond."
-
Only stock user can change data related warehouse therefore test with that user which have stock user rights,
-
!context
uid: 'res_stock_user'
-
I run the scheduler.
-
!python {model: procurement.order}: |
self.run_scheduler(cr, uid)
-
Salesman can also check order therefore test with that user which have salesman rights,
-
!context
uid: 'res_sale_stock_salesman'
-
I check the details of delivery order after confirmed quotation.
-
!python {model: sale.order}: |
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
sale_order = self.browse(cr, uid, ref("sale_order_service"))
assert sale_order.picking_ids, "Delivery order is not created."
for picking in sale_order.picking_ids:
assert picking.state == "auto" or "confirmed", "Delivery order should be in 'Waitting Availability' state."
assert picking.origin == sale_order.name,"Origin of Delivery order is not correspond with sequence number of sale order."
assert picking.picking_type_id == self.pool.get('ir.model.data').get_object(cr, uid, 'stock', 'picking_type_out', context=context),"Shipment should be Outgoing."
assert picking.move_type == sale_order.picking_policy,"Delivery Method is not corresponding with delivery method of sale order."
assert picking.partner_id.id == sale_order.partner_shipping_id.id,"Shipping Address is not correspond with sale order."
assert picking.note == sale_order.note,"Note is not correspond with sale order."
assert picking.invoice_state == (sale_order.order_policy=='picking' and '2binvoiced') or 'none',"Invoice policy is not correspond with sale order."
assert len(picking.move_lines) == len(sale_order.order_line) - 1, "Total move of delivery order are not corresposning with total sale order lines."
location_id = sale_order.warehouse_id.lot_stock_id.id
for move in picking.move_lines:
order_line = move.procurement_id.sale_line_id
date_planned = datetime.strptime(sale_order.date_order, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta(days=order_line.delay or 0.0)
date_planned = (date_planned - timedelta(days=sale_order.company_id.security_lead)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
assert datetime.strptime(move.date_expected, DEFAULT_SERVER_DATETIME_FORMAT) == datetime.strptime(date_planned, DEFAULT_SERVER_DATETIME_FORMAT), "Excepted Date is not correspond with Planned Date."
assert move.product_id.id == order_line.product_id.id,"Product is not correspond."
assert move.product_qty == order_line.product_uom_qty,"Product Quantity is not correspond."
assert move.product_uom.id == order_line.product_uom.id,"Product UOM is not correspond."
assert move.product_uos_qty == (order_line.product_uos and order_line.product_uos_qty or order_line.product_uom_qty), "Product UOS Quantity is not correspond."
assert move.product_uos.id == (order_line.product_uos and order_line.product_uos.id or order_line.product_uom.id), "Product UOS is not correspond"
assert move.product_packaging.id == order_line.product_packaging.id,"Product packaging is not correspond."
#assert move.location_id.id == location_id,"Source Location is not correspond."
-
Now, I dispatch delivery order.
-
!python {model: stock.picking}: |
order = self.pool.get('sale.order').browse(cr, uid, ref("sale_order_service"), context=context)
for pick in order.picking_ids:
data = pick.force_assign()
if data == True:
pick.do_transfer()
-
I run the scheduler.
-
!python {model: procurement.order}: |
self.run_scheduler(cr, uid)
-
I check sale order to verify shipment.
-
!python {model: sale.order}: |
order = self.pool.get('sale.order').browse(cr, uid, ref("sale_order_service"))
assert order.shipped == True, "Sale order is not Delivered."
#assert order.state == 'progress', 'Order should be in inprogress.'
assert len(order.invoice_ids) == False, "Invoice should not created on dispatch delivery order."
-
I create Invoice from Delivery Order.
-
!python {model: stock.invoice.onshipping}: |
sale = self.pool.get('sale.order')
sale_order = sale.browse(cr, uid, ref("sale_order_service"))
ship_ids = [x.id for x in sale_order.picking_ids]
wiz_id = self.create(cr, uid, {'journal_id': ref('sales_journal')},
{'active_ids': ship_ids, 'active_model': 'stock.picking'})
self.create_invoice(cr, uid, [wiz_id], {"active_ids": ship_ids, "active_id": ship_ids[0]})
-
I check the invoice details after dispatched delivery.
-
!python {model: sale.order}: |
from openerp.tools import float_compare
order = self.browse(cr, uid, ref("sale_order_service"))
assert order.invoice_ids, "Invoice is not created."
ac = order.partner_invoice_id.property_account_receivable_id.id
journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'sale'), ('company_id', '=', order.company_id.id)])
for invoice in order.invoice_ids:
assert invoice.type == 'out_invoice',"Invoice should be Customer Invoice."
assert invoice.account_id.id == ac,"Invoice account is not correspond."
assert invoice.reference == order.client_order_ref or order.name,"Reference is not correspond."
assert invoice.partner_id.id == order.partner_invoice_id.id,"Customer does not correspond."
assert invoice.currency_id.id == order.pricelist_id.currency_id.id, "Currency is not correspond."
assert (invoice.comment or '') == (order.note or ''),"Note is not correspond."
assert invoice.journal_id.id in journal_ids,"Sales Journal is not link on Invoice."
assert invoice.payment_term_id.id == order.payment_term_id.id, "Payment term is not correspond."
for so_line in order.order_line:
inv_line = so_line.invoice_lines[0]
ac = so_line.product_id.property_account_income_id.id or so_line.product_id.categ_id.property_account_income_categ_id.id
assert inv_line.product_id.id == so_line.product_id.id or False,"Product is not correspond"
assert inv_line.account_id.id == ac,"Account of Invoice line is not corresponding."
assert inv_line.uos_id.id == (so_line.product_uos and so_line.product_uos.id or so_line.product_uom.id), "Product UOS is not correspond."
assert float_compare(inv_line.price_unit, so_line.price_unit , precision_digits=2) == 0, "Price Unit is not correspond."
assert inv_line.quantity == (so_line.product_uos and so_line.product_uos_qty or so_line.product_uom_qty), "Product qty is not correspond."
assert inv_line.price_subtotal == so_line.price_subtotal, "Price sub total is not correspond."
-
Only Stock manager can open the Invoice therefore test with that user which have stock manager rights,
-
!context
uid: 'res_stock_manager'
-
I open the Invoice.
-
!python {model: sale.order}: |
so = self.browse(cr, uid, ref("sale_order_service"))
account_invoice_obj = self.pool.get('account.invoice')
for invoice in so.invoice_ids:
account_invoice_obj.signal_workflow(cr, uid, [invoice.id], '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_service"))
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])
-
To test process of the Sale Order with access rights of saleman,
-
!context
uid: 'res_sale_stock_salesman'
-
I check the order after paid invoice.
-
!python {model: sale.order}: |
order = self.browse(cr, uid, ref("sale_order_service"))
assert order.invoiced == True, "Sale order is not invoiced."
assert order.state == 'done', 'Order should be in closed.'
-
In order to test the Prepaid Order Policy, I create a product
-
!record {model: product.product, id: product_prepaid1}:
name: 'OpenERP Documentation Book'
list_price: 60.60
-
Now i create a sale order that uses my new product
-
!record {model: sale.order, id: sale_order_prepaid1}:
partner_id: base.res_partner_2
order_policy: prepaid
order_line:
- product_id: sale_stock.product_prepaid1
product_uom_qty: 10
-
Now I confirm the Quotation with "Pay before delivery" policy with access rights of salesman.
-
!context
uid: 'res_sale_stock_salesman'
-
!workflow {model: sale.order, action: order_confirm, ref: sale_order_prepaid1}
-
I check that delivery order should not created before invoice is paid.
-
!python {model: sale.order}: |
sale_order = self.browse(cr, uid, ref("sale_order_prepaid1"))
assert len(sale_order.picking_ids) == False, "Delivery order should not created before invoice."
assert sale_order.invoice_ids, "Invoice should be created."
-
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_3}:
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_3_line_1}:
order_id: sale_order_cl_3
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_3_line_2}:
order_id: sale_order_cl_3
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_3_line_1}: |
self.button_cancel()
-
I confirm the sale order
-
!workflow {model: sale.order, action: order_confirm, ref: sale_order_cl_3}
-
I check that no procurement has been generated for the canceled line
-
!assert {model: sale.order.line, id: sale_order_cl_3_line_1, string: The canceled line should not have a procurement}:
- not procurement_ids
-
I check that we have only 1 stock move, for the not canceled line
-
!python {model: sale.order, id: sale_order_cl_3}: |
moves = self.picking_ids.mapped('move_lines')
assert len(moves) == 1, "We should have 1 move, got %s" % len(moves)
-
Only sales manager Creates product so let's check with access rights of salemanager.
-
!context
uid: 'res_sale_stock_salesmanager'
-
In order to test the onchange of the Sale Order, I create a product
-
!record {model: product.product, id: product_onchange1}:
name: 'Devil Worship Book'
lst_price: 66.6
default_code: 'DWB00001'
-
In sale order to test process of onchange of Sale Order with access rights of saleman.
-
!context
uid: 'res_sale_stock_salesman'
-
Now i create a sale order that uses my new product
-
!record {model: sale.order, id: sale_order_onchange1}:
partner_id: base.res_partner_2
order_line:
- product_id: sale_stock.product_onchange1
product_uom_qty: 10
-
I verify that the onchange of product on sale order line was correctly triggered
-
!python {model: sale.order}: |
from openerp.tools import float_compare
order_line = self.browse(cr, uid, ref('sale_order_onchange1')).order_line
assert order_line[0].name == u'[DWB00001] Devil Worship Book', "The onchange function of product was not correctly triggered"
assert float_compare(order_line[0].price_unit, 66.6, precision_digits=2) == 0, "The onchange function of product was not correctly triggered"
-
Create a user as 'Stock Salesmanager'
-
!record {model: res.users, id: res_sale_stock_salesmanager, view: False}:
company_id: base.main_company
name: Stock Sales manager
login: ssm
email: ss_salesmanager@yourcompany.com
-
I added groups for Salesmanager.
-
!record {model: res.users, id: res_sale_stock_salesmanager}:
groups_id:
- base.group_sale_manager
-
Create a user as 'Stock Salesman'
-
!record {model: res.users, id: res_sale_stock_salesman, view: False}:
company_id: base.main_company
name: Stock Salesman
login: ssu
email: ss_salesman@yourcompany.com
-
I added groups for Stock Salesman.
-
!record {model: res.users, id: res_sale_stock_salesman}:
groups_id:
- base.group_sale_salesman_all_leads
- stock.group_stock_user
-
Create a user as 'Stock User'
-
!record {model: res.users, id: res_stock_user, view: False}:
company_id: base.main_company
name: Stock User
login: sau
email: stock_user@yourcompany.com
-
I added groups for Stock User.
-
!record {model: res.users, id: res_stock_user}:
groups_id:
- stock.group_stock_user
-
Create a user as 'Stock Manager'
-
!record {model: res.users, id: res_stock_manager, view: False}:
company_id: base.main_company
name: Stock Manager
login: sam
email: stock_manager@yourcompany.com
-
I added groups for Stock Manager.
-
!record {model: res.users, id: res_stock_manager}:
groups_id:
- stock.group_stock_manager
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment