[IMP] purchase: adaptation due to the new Purchase module

Major changes:
- No generation of invoice from PO
- Remove workflow

Reason: complete rewrite of the Purchase module.

Responsible: fp, nim
This commit is contained in:
Nicolas Martinelli
2015-09-02 08:19:56 +02:00
parent 826661d53a
commit cb01be235e
36 changed files with 1117 additions and 3559 deletions
+1 -1
View File
@@ -5,8 +5,8 @@ import mail_mail
import purchase
import partner
import stock
import wizard
import report
import stock
import company
import res_config
import invoice
+1 -9
View File
@@ -30,13 +30,11 @@ Dashboard / Reports for Purchase Management will include:
'data': [
'security/purchase_security.xml',
'security/ir.model.access.csv',
'purchase_workflow.xml',
'invoice_view.xml',
'purchase_sequence.xml',
'company_view.xml',
'purchase_data.xml',
'purchase_data.yml',
'wizard/purchase_order_group_view.xml',
'wizard/purchase_line_invoice_view.xml',
'purchase_report.xml',
'purchase_view.xml',
'stock_view.xml',
@@ -57,15 +55,9 @@ Dashboard / Reports for Purchase Management will include:
'test/fifo_returns.yml',
# 'test/costmethodchange.yml',
'test/process/cancel_order.yml',
'test/process/rfq2order2done.yml',
'test/process/generate_invoice_from_reception.yml',
'test/process/merge_order.yml',
'test/process/invoice_on_poline.yml',
'test/ui/duplicate_order.yml',
'test/ui/delete_order.yml',
'test/average_price.yml',
'test/anglo_saxon.yml',
'test/anglo_saxon_avg_fifo.yml',
],
'demo': [
'purchase_order_demo.yml',
+8 -13
View File
@@ -1,18 +1,13 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.osv import osv,fields
from openerp import api, fields, models, _
class company(osv.osv):
class company(models.Model):
_inherit = 'res.company'
_columns = {
'po_lead': fields.float(
'Purchase Lead Time', required=True,
help="Margin of error for vendor lead times. When the system "\
"generates Purchase Orders for procuring products, "\
"they will be scheduled that many days earlier "\
"to cope with unexpected vendor delays."),
}
_defaults = {
'po_lead': lambda *a: 1.0,
}
po_lead = fields.Float(string='Purchase Lead Time', required=True,
help="Margin of error for vendor lead times. When the system "\
"generates Purchase Orders for procuring products, "\
"they will be scheduled that many days earlier "\
"to cope with unexpected vendor delays.", default=1.0)
+132
View File
@@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp import api, fields, models, _
from openerp.tools.float_utils import float_compare
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
purchase_id = fields.Many2one('purchase.order', string='Purchase Order', domain=[('invoice_status', '=', 'to invoice')])
# Load all unsold PO lines
@api.onchange('purchase_id')
def purchase_order_change(self):
result = []
if not self.purchase_id:
return {}
if not self.partner_id:
self.partner_id = self.purchase_id.partner_id.id
done = False
for line in self.purchase_id.order_line:
if line.product_id.purchase_method == 'purchase':
qty = line.product_qty - line.qty_invoiced
else:
qty = line.qty_received - line.qty_invoiced
if float_compare(qty, 0.0, precision_rounding=line.product_uom.rounding) <= 0:
continue
done = True
account = self.env['account.invoice.line'].get_invoice_line_account('in_invoice', line.product_id, self.purchase_id.fiscal_position_id, self.env.user.company_id)
taxes = line.taxes_id or line.product_id.supplier_taxes_id
invoice_line_tax_ids = self.purchase_id.fiscal_position_id.map_tax(taxes)
result.append({
'purchase_line_id': line.id,
'name': line.name,
'origin': self.purchase_id.origin,
'uom_id': line.product_uom.id,
'product_id': line.product_id.id,
'account_id': account,
'price_unit': line.price_unit,
'quantity': qty,
'discount': 0.0,
'account_analytic_id': line.account_analytic_id.id,
'invoice_line_tax_ids': invoice_line_tax_ids
})
self.invoice_line_ids = result
if not done:
warning = {
'title': _('Bill Control Warning!'),
'message' : _('None of the products from this purchase order can be billed. You should control the purchase order.')
}
return {'warning': warning}
class AccountInvoiceLine(models.Model):
""" Override AccountInvoice_line to add the link to the purchase order line it is related to"""
_inherit = 'account.invoice.line'
purchase_line_id = fields.Many2one('purchase.order.line', 'Purchase Order Line', ondelete='set null', select=True, readonly=True)
@api.model
def move_line_get(self, invoice_id):
res = super(AccountInvoiceLine, self).move_line_get(invoice_id)
invoice = self.browse(invoice_id)
if self.env.user.company_id.anglo_saxon_accounting:
if invoice.type in ['in_invoice', 'in_refund']:
for i_line in invoice.invoice_line_ids:
res.extend(self._anglo_saxon_purchase_move_lines(i_line, res))
return res
@api.model
def _anglo_saxon_purchase_move_lines(self, i_line, res):
"""Return the additional move lines for purchase invoices and refunds.
i_line: An account.invoice.line object.
res: The move line entries produced so far by the parent move_line_get.
"""
inv = i_line.invoice_id
company_currency = inv.company_id.currency_id
if i_line.product_id and i_line.product_id.valuation == 'real_time':
if i_line.product_id.type != 'service':
# get the price difference account at the product
acc = i_line.product_id.property_account_creditor_price_difference and i_line.product_id.property_account_creditor_price_difference.id
if not acc:
# if not found on the product get the price difference account at the category
acc = i_line.product_id.categ_id.property_account_creditor_price_difference_categ and i_line.product_id.categ_id.property_account_creditor_price_difference_categ.id
a = None
# oa will be the stock input account
# first check the product, if empty check the category
oa = i_line.product_id.property_stock_account_input and i_line.product_id.property_stock_account_input.id
if not oa:
oa = i_line.product_id.categ_id.property_stock_account_input_categ_id and i_line.product_id.categ_id.property_stock_account_input_categ_id.id
if oa:
# get the fiscal position
fpos = i_line.invoice_id.fiscal_position_id or False
a = fpos.map_account(oa)
diff_res = []
account_prec = inv.company_id.currency_id.decimal_places
# calculate and write down the possible price difference between invoice price and product price
for line in res:
if line.get('invl_id', 0) == i_line.id and a == line['account_id']:
uom = i_line.product_id.uom_id
valuation_price_unit = uom._compute_price(i_line.product_id.standard_price, i_line.uom_id.id)
if i_line.product_id.cost_method != 'standard' and i_line.purchase_line_id:
#for average/fifo/lifo costing method, fetch real cost price from incomming moves
stock_move_obj = self.env['stock.move']
valuation_stock_move = stock_move_obj.search([('purchase_line_id', '=', i_line.purchase_line_id.id)], limit=1)
if valuation_stock_move:
valuation_price_unit = valuation_stock_move[0].price_unit
if inv.currency_id.id != company_currency.id:
valuation_price_unit = company_currency.compute(inv.currency_id, valuation_price_unit, context={'date': inv.date_invoice})
if valuation_price_unit != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc:
# price with discount and without tax included
price_unit = self.env['account.tax'].compute_all(line['taxes'], i_line.price_unit * (1-(i_line.discount or 0.0)/100.0),\
inv.currency_id.id, line['quantity'])['total_excluded']
price_line = round(valuation_price_unit * line['quantity'], account_prec)
price_diff = round(price_unit - price_line, account_prec)
line.update({'price': price_line})
diff_res.append({
'type': 'src',
'name': i_line.name[:64],
'price_unit': round(price_diff / line['quantity'], account_prec),
'quantity': line['quantity'],
'price': price_diff,
'account_id': acc,
'product_id': line['product_id'],
'uom_id': line['uom_id'],
'account_analytic_id': line['account_analytic_id'],
'taxes': line.get('taxes', []),
})
return diff_res
return []
+68
View File
@@ -0,0 +1,68 @@
<odoo>
<record id="action_invoice_pending" model="ir.actions.act_window">
<field name="name">Vendor Bills</field>
<field name="res_model">account.invoice</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar,pivot,graph</field>
<field eval="False" name="view_id"/>
<field name="domain">[('type','=','in_invoice')]</field>
<field name="context">{'default_type':'in_invoice', 'type':'in_invoice', 'journal_type': 'purchase'}</field>
<field name="search_view_id" ref="account.view_account_invoice_filter"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a draft invoice.
</p><p>
Use this menu to control the invoices to be received from your
vendor. When registering a new bill, set the purchase order
and Odoo will fill the bill automatically according to ordered
or received quantities.
</p>
</field>
</record>
<record id="purchase_open_invoice" model="ir.actions.act_window">
<field name="name">Vendor Bills</field>
<field name="res_model">account.invoice</field>
<field name="view_type">form</field>
<field name="view_mode">tree,kanban,form,calendar,pivot,graph</field>
<field eval="False" name="view_id"/>
<field name="domain">[('type','in',('in_invoice', 'in_refund')),('purchase_id','=',active_id)]</field>
<field name="context">{'default_type': 'in_invoice', 'type': 'in_invoice', 'journal_type': 'purchase', 'default_purchase_id': active_id}</field>
<field name="search_view_id" ref="account.view_account_invoice_filter"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to record a vendor bill related to this purchase.
</p>
<p>
You can control the invoice from your vendor according to
what you purchased (services) or received (products).
</p>
</field>
</record>
<record id="action_invoice_supplier_tree1_view1" model="ir.actions.act_window.view">
<field eval="1" name="sequence"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="account.invoice_supplier_tree"/>
<field name="act_window_id" ref="purchase_open_invoice"/>
</record>
<record id="action_invoice__supplier_tree1_view2" model="ir.actions.act_window.view">
<field eval="2" name="sequence"/>
<field name="view_mode">form</field>
<field name="view_id" ref="account.invoice_supplier_form"/>
<field name="act_window_id" ref="purchase_open_invoice"/>
</record>
<record id="view_invoice_supplier_purchase_form" model="ir.ui.view">
<field name="name">account.invoice.supplier.purchase</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_supplier_form"/>
<field name="arch" type="xml">
<field name="reference" position="after" >
<field name="purchase_id" domain="[('invoice_status', '=', 'to invoice'), ('partner_id', '=', partner_id)]" attrs="{'invisible': [('state', '&lt;&gt;', 'draft')]}" class="oe_edit_only"/>
</field>
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='company_id']" position="after">
<field name="purchase_line_id" invisible="1"/>
</xpath>
</field>
</record>
</odoo>
+16 -23
View File
@@ -1,32 +1,25 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.osv import fields, osv
from openerp import api, fields, models
class res_partner(osv.osv):
class res_partner(models.Model):
_name = 'res.partner'
_inherit = 'res.partner'
def _purchase_invoice_count(self, cr, uid, ids, field_name, arg, context=None):
PurchaseOrder = self.pool['purchase.order']
Invoice = self.pool['account.invoice']
return {
partner_id: {
'purchase_order_count': PurchaseOrder.search_count(cr,uid, [('partner_id', 'child_of', partner_id)], context=context),
'supplier_invoice_count': Invoice.search_count(cr,uid, [('partner_id', 'child_of', partner_id), ('type','=','in_invoice')], context=context)
}
for partner_id in ids
}
@api.multi
def _purchase_invoice_count(self):
PurchaseOrder = self.env['purchase.order']
Invoice = self.env['account.invoice']
for partner in self:
partner.purchase_order_count = PurchaseOrder.search_count([('partner_id', 'child_of', partner.id)])
partner.supplier_invoice_count = Invoice.search_count([('partner_id', 'child_of', partner.id), ('type', '=', 'in_invoice')])
def _commercial_fields(self, cr, uid, context=None):
return super(res_partner, self)._commercial_fields(cr, uid, context=context)
@api.model
def _commercial_fields(self):
return super(res_partner, self)._commercial_fields()
_columns = {
'property_purchase_currency_id': fields.property(
type='many2one',
relation='res.currency',
string="Supplier Currency",
help="This currency will be used, instead of the default one, for purchases from the current partner"),
'purchase_order_count': fields.function(_purchase_invoice_count, string='# of Purchase Order', type='integer', multi="count"),
'supplier_invoice_count': fields.function(_purchase_invoice_count, string='# Vendor Bills', type='integer', multi="count"),
}
property_purchase_currency_id = fields.Many2one('res.currency', string="Supplier Currency",\
help="This currency will be used, instead of the default one, for purchases from the current partner")
purchase_order_count = fields.Integer(compute='_purchase_invoice_count', string='# of Purchase Order')
supplier_invoice_count = fields.Integer(compute='_purchase_invoice_count', string='# Vendor Bills')
+665 -1712
View File
File diff suppressed because it is too large Load Diff
+68 -19
View File
@@ -3,86 +3,135 @@
-
!record {model: purchase.order, id: purchase_order_1}:
partner_id: base.res_partner_1
invoice_method: order
order_line:
- product_id: product.product_product_15
price_unit: 79.80
product_qty: 15.0
- product_id: product.product_product_25
price_unit: 2868.70
product_qty: 5.0
- product_id: product.product_product_27
price_unit: 3297.20
product_qty: 4.0
-
!record {model: purchase.order.line, id: purchase_order_line_1}:
order_id: purchase.purchase_order_1
product_id: product.product_product_15
name: RAM SR3
price_unit: 79.80
product_qty: 15.0
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
-
!record {model: purchase.order.line, id: purchase_order_line_2}:
order_id: purchase_order_1
product_id: product.product_product_25
name: Laptop E5023
price_unit: 2868.70
product_qty: 5.0
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
-
!record {model: purchase.order.line, id: purchase_order_line_3}:
order_id: purchase_order_1
product_id: product.product_product_27
name: Laptop Customized
price_unit: 3297.20
product_qty: 4.0
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
-
Creating second order
-
!record {model: purchase.order, id: purchase_order_2}:
partner_id: base.res_partner_3
invoice_method: picking
order_line:
- product_id: product.product_product_31
name: Multimedia Speakers
price_unit: 132.50
product_qty: 20.0
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
- product_id: product.product_product_29
name: Pen drive, SP-2
price_unit: 89
product_qty: 5
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
-
!record {model: purchase.order, id: purchase_order_3}:
partner_id: base.res_partner_12
order_line:
- product_id: product.product_product_2
name: Support Services
price_unit: 25.50
product_qty: 10.0
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
-
!record {model: purchase.order, id: purchase_order_4}:
partner_id: base.res_partner_4
order_line:
- product_id: product.product_product_14
name: RAM SR2 (kit)
price_unit: 85.50
product_qty: 6.0
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
- product_id: product.product_product_20
name: Motherboard I9P57
price_unit: 1690
product_qty: 5.0
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
- product_id: product.product_product_6
name: iPad Mini
price_unit: 800
product_qty: 7.0
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
-
!record {model: purchase.order, id: purchase_order_5}:
partner_id: base.res_partner_2
order_line:
- product_id: product.product_product_22
name: Processor Core i5 2.70 Ghz
product_qty: 3
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
- product_id: product.product_product_24
name: Graphics Card
product_qty: 3
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
-
!record {model: purchase.order, id: purchase_order_6}:
partner_id: base.res_partner_1
order_line:
- product_id: product.product_product_38
name: Ink Cartridge
price_unit: 58
product_qty: 9
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
- product_id: product.product_product_39
name: Toner Cartridge
product_qty: 3
price_unit: 65
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
- product_id: product.product_product_44
name: GrapWorks Software
product_qty: 4
price_unit: 154.5
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
-
!record {model: purchase.order, id: purchase_order_7}:
partner_id: base.res_partner_4
order_line:
- product_id: product.product_product_12
name: Mouse, Wireless
product_qty: 5
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
- product_id: product.product_product_34
name: Webcam
product_qty: 15
-
!python {model: purchase.order} : |
account_id = self.pool.get('account.account').search(cr, uid, [('user_type_id', '=', ref('account.data_account_type_expenses'))])
if account_id:
self.signal_workflow(cr, uid, [ref('purchase_order_2')], 'purchase_confirm')
self.signal_workflow(cr, uid, [ref('purchase_order_6')], 'purchase_confirm')
product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d')
+105 -251
View File
@@ -18,9 +18,10 @@
<menuitem
id="menu_purchase_config_pricelist" name="Pricelists"
parent="menu_purchase_config" sequence="20" groups="base.group_no_one"/>
<menuitem
action="product.product_supplierinfo_type_action" id="menu_product_pricelist_action2_purchase"
parent="menu_purchase_config_pricelist" sequence="1" groups="base.group_no_one"/>
action="product.product_supplierinfo_type_action" id="menu_product_pricelist_action2_purchase"
parent="menu_purchase_config_pricelist" sequence="1" groups="base.group_no_one"/>
<menuitem
id="menu_product_in_config_purchase" name="Products"
@@ -50,39 +51,16 @@
<!-- Purchase Control Menu -->
<menuitem id="menu_purchase_control" name="Control" parent="base.menu_purchase_root" sequence="4"/>
<!--Inventory control-->
<menuitem id="menu_procurement_management_inventory" name="Products"
parent="menu_purchase_control" sequence="4"/>
<!--Inventory control-->
<menuitem action="stock.action_receipt_picking_move" id="menu_action_picking_tree_in_move"
parent="menu_procurement_management_inventory" sequence="11"/>
parent="menu_purchase_control" sequence="11"/>
<!--Invoice control-->
<menuitem id="menu_procurement_management_invoice" name="Bills"
parent="menu_purchase_control" sequence="6"/>
<record id="action_invoice_pending" model="ir.actions.act_window">
<field name="name">Draft Bills</field>
<field name="res_model">account.invoice</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar,pivot,graph</field>
<field eval="False" name="view_id"/>
<field name="domain">[('type','=','in_invoice')]</field>
<field name="context">{'default_type':'in_invoice', 'type':'in_invoice', 'journal_type': 'purchase', 'search_default_draft': 1}</field>
<field name="search_view_id" ref="account.view_account_invoice_filter"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a draft invoice.
</p><p>
Use this menu to control the invoices to be received from your
vendor. Odoo generates draft invoices from your purchase
orders or receipts, according to your settings.
</p><p>
Once you receive a vendor bill, you can match it with the
draft invoice and validate it.
</p>
</field>
</record>
<menuitem
id="menu_procurement_management_pending_invoice"
action="action_invoice_pending"
parent="menu_purchase_control"
sequence="13"/>
<record id="product_normal_action_puchased" model="ir.actions.act_window">
<field name="name">Products</field>
@@ -108,13 +86,6 @@
</field>
</record>
<menuitem
id="menu_procurement_management_pending_invoice"
action="action_invoice_pending"
parent="menu_procurement_management_invoice"
sequence="13"/>
<!-- Product menu-->
<menuitem name="Products" id="menu_procurement_partner_contact_form" action="product_normal_action_puchased"
parent="menu_procurement_management" sequence="20"/>
@@ -124,7 +95,7 @@
<field name="model">purchase.order</field>
<field name="priority" eval="2"/>
<field name="arch" type="xml">
<calendar string="Calendar View" date_start="minimum_planned_date" color="partner_id">
<calendar string="Calendar View" date_start="date_planned" color="partner_id">
<field name="name"/>
<field name="amount_total" widget="monetary"/>
<field name="partner_id"/>
@@ -152,30 +123,49 @@
</field>
</record>
<record id="purchase_open_picking" model="ir.actions.act_window">
<field name="name">Receptions</field>
<field name="res_model">stock.picking</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('purchase_id', '=', active_id)]</field>
</record>
<record id="purchase_order_form" model="ir.ui.view">
<field name="name">purchase.order.form</field>
<field name="model">purchase.order</field>
<field name="arch" type="xml">
<form string="Purchase Order">
<header>
<button name="bid_received" states="sent" string="Bid Received" class="oe_highlight"/>
<button name="wkf_send_rfq" states="draft" string="Send RFQ by Email" type="object" context="{'send_rfq':True}" class="oe_highlight"/>
<button name="wkf_send_rfq" states="sent" string="Re-Send RFQ by Email" type="object" context="{'send_rfq':True}"/>
<button name="action_rfq_send" states="draft" string="Send RFQ by Email" type="object" context="{'send_rfq':True}" class="oe_highlight"/>
<button name="action_rfq_send" states="sent" string="Re-Send RFQ by Email" type="object" context="{'send_rfq':True}"/>
<button name="print_quotation" string="Print RFQ" type="object" states="draft" class="oe_highlight" groups="base.group_user"/>
<button name="print_quotation" string="Re-Print RFQ" type="object" states="sent" groups="base.group_user"/>
<button name="purchase_confirm" states="draft" string="Confirm Order" id="draft_confirm"/>
<button name="purchase_confirm" states="bid" string="Confirm Order" class="oe_highlight" id="bid_confirm"/>
<button name="picking_ok" states="except_picking" string="Manually Corrected"/>
<button name="invoice_ok" states="except_invoice" string="Manually Corrected"/>
<button name="purchase_approve" states="confirmed" string="Approve Order" class="oe_highlight" groups="purchase.group_purchase_manager"/>
<button name="wkf_send_rfq" states="approved" string="Send PO by Email" type="object" context="{'send_rfq':False}"/>
<button name="view_picking" string="Receive Products" type="object" attrs="{'invisible': ['|', ('shipped','=',True), ('state','!=', 'approved')]}" class="oe_highlight"/>
<button name="view_invoice" string="Receive Invoice" type="object" attrs="{'invisible': ['|', ('invoice_method','in', ['picking', 'manual']), '|', ('state','!=', 'approved'), ('invoiced','=',True) ]}" class="oe_highlight"/>
<button name="action_cancel_draft" states="cancel,sent,confirmed" string="Set to Draft" type="object" />
<button name="action_cancel" states="draft,confirmed,sent,bid,approved,except_picking,except_invoice" string="Cancel" type="object" />
<field name="state" widget="statusbar" statusbar_visible="draft,sent,bid,approved,done" statusbar_colors='{"except_picking":"red","except_invoice":"red","confirmed":"blue"}' readonly="1"/>
<button name="button_confirm" type="object" states="draft" string="Confirm Order" id="draft_confirm"/>
<button name="button_confirm" type="object" states="sent" string="Confirm Order" class="oe_highlight" id="bid_confirm"/>
<button name="button_approve" type="object" states="to approve" string="Approve Order" class="oe_highlight" groups="purchase.group_purchase_manager"/>
<button name="action_rfq_send" states="approved" string="Send PO by Email" type="object" context="{'send_rfq':False}"/>
<button name="%(purchase_open_picking)d" string="Receive Products" type="action" attrs="{'invisible': [('state','not in', ('purchase','done'))]}"/>
<button name="button_draft" states="cancel" string="Set to Draft" type="object" />
<button name="button_cancel" states="draft,to approve,sent,purchase" string="Cancel" type="object" />
<button name="button_done" type="object" string="Set to Done" states="purchase"
help="If a purchase order is done, you can not modify it manually anymore. But you will still be able to bill or receive."/>
<field name="state" widget="statusbar" statusbar_visible="draft,sent,purchase,done" readonly="1"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button type="action"
name="%(purchase_open_picking)d"
class="oe_stat_button"
icon="fa-truck">
<field name="picking_count" widget="statinfo" string="Shipment" help="Incoming Shipments"/>
</button>
<button type="action" name="%(purchase_open_invoice)d"
class="oe_stat_button"
icon="fa-pencil-square-o">
<field name="invoice_count" widget="statinfo" string="Invoices"/>
</button>
</div>
<div class="oe_title">
<label string="Request for Quotation " attrs="{'invisible': [('state','not in',('draft','sent','bid'))]}"/>
<label string="Purchase Order " attrs="{'invisible': [('state','in',('draft','sent','bid'))]}"/>
@@ -185,81 +175,63 @@
</div>
<group>
<group>
<field name="partner_id" on_change="onchange_partner_id(partner_id, context)" context="{'search_default_supplier':1, 'default_supplier':1, 'default_customer':0}" domain="[('supplier','=',True)]"/>
<field name="partner_id" context="{'search_default_supplier':1, 'default_supplier':1, 'default_customer':0}" domain="[('supplier','=',True)]"/>
<field name="partner_ref"/>
<field name="currency_id" groups="base.group_multi_currency"/>
<field name="journal_id" invisible='1'/>
</group>
<group>
<field name="date_order"/>
<field name="origin" attrs="{'invisible': [('origin','=',False)]}"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
<field name="related_usage" invisible="1"/>
<field name="bid_date" invisible="1"/>
<field name="bid_validity" attrs="{'invisible':[('bid_date','=',False)]}"/>
<field name="dest_address_id" string="Customer Address" on_change="onchange_dest_address_id(dest_address_id, context)"
attrs="{'invisible':[('related_usage','!=','customer')],
'required': [('related_usage','=', 'customer')]}"
groups="stock.group_locations"/>
</group>
</group>
<notebook>
<page string="Products">
<field name="order_line">
<tree string="Purchase Order Lines" editable="bottom">
<field name="product_id"
on_change="onchange_product_id(product_id, 0, False,
parent.partner_id, parent.date_order, parent.fiscal_position_id, date_planned,
name, False, parent.state, True, parent.currency_id,context)"
context="{'partner_id': parent.partner_id}"/>
<field name="product_id" context="{'partner_id': parent.partner_id}"/>
<field name="name"/>
<field name="date_planned"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
<field name="account_analytic_id" context="{'default_partner_id':parent.partner_id}" groups="purchase.group_analytic_accounting" domain="[('type','not in',('view','template'))]"/>
<field name="product_qty"
on_change="onchange_product_id(product_id, product_qty,
product_uom, parent.partner_id, parent.date_order, parent.fiscal_position_id,
date_planned, name, False, parent.state, False, parent.currency_id, context)"/>
<field name="product_uom" groups="product.group_uom" on_change="onchange_product_uom(product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position_id,date_planned,name,False,parent.state,parent.currency_id,context)"/>
<field name="product_qty"/>
<field name="qty_received" invisible="not context.get('show_purchase', False)"/>
<field name="qty_invoiced" invisible="not context.get('show_purchase', False)"/>
<field name="product_uom" groups="product.group_uom"/>
<field name="price_unit"/>
<field name="taxes_id" widget="many2many_tags" domain="[('type_tax_use','=','purchase')]"/>
<field name="price_subtotal" widget="monetary"/>
<field name="state" invisible="1"/>
</tree>
<form>
<group>
<form string="Purchase Order Line">
<sheet>
<group>
<field name="product_id"
on_change="onchange_product_id(product_id, 0, False,
parent.partner_id, parent.date_order, parent.fiscal_position_id, date_planned,
name, False, parent.state, True, parent.currency_id, context)"
context="{'partner_id': parent.partner_id}"/>
<label for="product_qty"/>
<div>
<field name="product_qty" class="oe_inline"
on_change="onchange_product_id(product_id, product_qty,
product_uom, parent.partner_id, parent.date_order, parent.fiscal_position_id,
date_planned, name, False, parent.state, False, parent.currency_id, context)"/>
<field name="product_uom" groups="product.group_uom" class="oe_inline"
on_change="onchange_product_uom(product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position_id,date_planned,name,False,parent.state,parent.currency_id,context)"/>
</div>
<field name="price_unit"/>
<group>
<field name="product_id"
context="{'partner_id': parent.partner_id}"/>
<label for="product_qty"/>
<div>
<field name="product_qty"
class="oe_inline"/>
<field name="product_uom" groups="product.group_uom" class="oe_inline"/>
</div>
<field name="price_unit"/>
</group>
<group>
<field name="taxes_id" widget="many2many_tags" domain="[('type_tax_use', '=', 'purchase')]"/>
<field name="date_planned" widget="date"/>
<field name="account_analytic_id" colspan="2" groups="purchase.group_analytic_accounting"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
</group>
</group>
<group>
<field name="taxes_id" widget="many2many_tags" domain="[('type_tax_use', '=', 'purchase')]"/>
<field name="date_planned" widget="date"/>
<field name="account_analytic_id" colspan="2" groups="purchase.group_analytic_accounting"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
</group>
</group>
<notebook>
<page string="Notes">
<field name="name"/>
</page><page string="Invoices and Incoming Shipments">
<field name="invoice_lines"/>
<field name="move_ids"/>
</page>
</notebook>
<notebook>
<page string="Notes">
<field name="name"/>
</page><page string="Invoices and Incoming Shipments">
<field name="invoice_lines"/>
<field name="move_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
<group class="oe_subtotal_footer oe_right">
@@ -267,8 +239,6 @@
<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" 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>
@@ -278,19 +248,14 @@
<page string="Deliveries &amp; Invoices">
<group>
<group>
<field name="minimum_planned_date"/>
<field name="picking_type_id" on_change="onchange_picking_type_id(picking_type_id, context)" domain="[('code','=','incoming')]" options="{'no_create': True}" context="{'special_shortened_wh_name': True}" groups="stock.group_locations"/>
<field name="location_id" groups="stock.group_locations" string="Location"/>
<field name="shipped" groups="base.group_no_one"/>
<field name="date_planned"/>
<field name="picking_type_id" domain="[('code','=','incoming')]" options="{'no_create': True}" context="{'special_shortened_wh_name': True}" groups="stock.group_locations"/>
<field name="incoterm_id"/>
</group>
<group>
<field name="invoice_method"/>
<field name="invoiced" invisible="1"/>
<field name="payment_term_id" options="{'no_open': True, 'no_create': True}"/>
<field name="fiscal_position_id" attrs="{'readonly': [('invoiced','=', True)]}" />
<!-- We do not need these fields anymore, the information is in open chatter -->
<field name="validator" groups="base.group_no_one"/>
<field name="invoice_status"/>
<field name="payment_term_id" options="{'no_open': True, 'no_create': True}" attrs="{'readonly': [('invoice_status','=', 'invoiced')]}"/>
<field name="fiscal_position_id" attrs="{'readonly': [('invoice_status','=', 'invoiced')]}" />
<field name="date_approve" groups="base.group_no_one"/>
</group>
</group>
@@ -305,7 +270,7 @@
</field>
</record>
<record id="view_request_for_quotation_filter" model="ir.ui.view">
<record id="view_purchase_order_filter" model="ir.ui.view">
<field name="name">request.quotation.select</field>
<field name="model">purchase.order</field>
<field name="arch" type="xml">
@@ -314,45 +279,21 @@
<field name="partner_id" operator="child_of"/>
<field name="product_id"/>
<field name="create_uid"/>
<filter name="draft" string="Quotations" domain="[('state','=','draft')]"/>
<filter name="approved" string="Approved" domain="[('state','in',('approved','done'))]"/>
<filter name="exception" string="Exception" domain="[('state','in',('except_invoice','except_picking'))]"/>
<filter name="draft" string="Quotations" domain="[('state','in',('draft','sent','to approve'))]"/>
<filter name="approved" string="Purchase Orders" domain="[('state','in',('purchase','done'))]"/>
<separator/>
<filter name="not_invoiced" string="Not Invoiced" domain="[('invoice_ids','=', False)]" help="Purchase orders that include lines not invoiced."/>
<filter name="not_invoiced" string="Not Invoiced" domain="[('invoice_status','=', 'to invoice')]" help="Purchase orders that include lines not invoiced."/>
<filter name="invoiced" string="Invoiced" domain="[('invoice_status','=', 'invoiced')]" help="Purchase orders that include lines not invoiced."/>
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
<group expand="0" string="Group By">
<filter string="Vendor" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Order Date" domain="[]" context="{'group_by':'date_order'}"/>
<filter string="Expected Date" domain="[]" context="{'group_by':'minimum_planned_date'}"/>
<filter string="Expected Date" domain="[]" context="{'group_by':'date_planned'}"/>
</group>
</search>
</field>
</record>
<record id="view_purchase_order_filter" model="ir.ui.view">
<field name="name">purchase.order.list.select</field>
<field name="model">purchase.order</field>
<field name="arch" type="xml">
<search string="Search Purchase Order">
<field name="name" string="Reference"/>
<field name="partner_id" operator="child_of"/>
<field name="product_id"/>
<field name="create_uid"/>
<filter name="draft" string="Quotations" domain="[('state','in',('draft','sent'))]"/>
<filter name="approved" string="Purchase Orders" domain="[('state','not in',('draft','cancel'))]"/>
<filter name="todo" string="To Do" domain="[('state','not in',('cancel','done'))]"/>
<filter name="exception" string="Exception" domain="[('state','in',('except_invoice','except_picking'))]"/>
<separator/>
<filter name="not_invoiced" string="Not Invoiced" domain="[('invoice_ids','=', False)]"/>
<separator/>
<filter string="Important Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
<group expand="0" string="Group By">
<filter string="Vendor" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Order Month" domain="[]" context="{'group_by':'date_order'}"/>
<filter string="Expected Month" domain="[]" context="{'group_by':'minimum_planned_date'}"/>
</group>
</search>
</field>
</record>
<!-- Purchase Orders Kanban View -->
<record model="ir.ui.view" id="view_sale_order_kanban">
@@ -381,7 +322,7 @@
<span><t t-esc="record.name.value"/> <t t-esc="record.date_order.value and record.date_order.value.split(' ')[0] or False"/></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', 'except_invoice'].indexOf(record.state.raw_value) > -1 ? 'label-danger' : ['approved'].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' : ['approved'].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>
</div>
</div>
</div>
@@ -395,13 +336,13 @@
<field name="name">purchase.order.tree</field>
<field name="model">purchase.order</field>
<field name="arch" type="xml">
<tree decoration-bf="message_needaction==True" decoration-muted="state=='cancel'" decoration-info="state in ('wait','confirmed')" decoration-danger="state in ('except_invoice','except_picking')" string="Purchase Order">
<field name="message_needaction" invisible="1"/>
<tree decoration-bf="message_unread==True" decoration-muted="state=='cancel'" decoration-info="state in ('wait','confirmed')" string="Purchase Order">
<field name="message_unread" invisible="1"/>
<field name="name" string="Reference"/>
<field name="date_order" />
<field name="partner_id"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
<field name="minimum_planned_date" invisible="context.get('quotation_only', False)"/>
<field name="date_planned" invisible="context.get('quotation_only', False)"/>
<field name="origin"/>
<field name="amount_untaxed" sum="Total Untaxed amount" string="Untaxed" widget="monetary"/>
<field name="amount_total" sum="Total amount" widget="monetary"/>
@@ -440,7 +381,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">purchase.order</field>
<field name="view_mode">tree,kanban,form,pivot,graph,calendar</field>
<field name="context">{'search_default_todo':1}</field>
<field name="context">{'search_default_todo':1, 'show_purchase': True}</field>
<field name="domain">[('state','not in',('draft','sent','bid', 'confirmed'))]</field>
<field name="search_view_id" ref="view_purchase_order_filter"/>
<field name="help" type="html">
@@ -456,42 +397,6 @@
</record>
<menuitem action="purchase_form_action" id="menu_purchase_form_action" parent="menu_procurement_management" sequence="6"/>
<record id="purchase_order_line_form" model="ir.ui.view">
<field name="name">purchase.order.line.form</field>
<field name="model">purchase.order.line</field>
<field name="arch" type="xml">
<form string="Purchase Order Line">
<sheet>
<group>
<group>
<field name="product_id"/>
<label for="product_qty"/>
<div>
<field name="product_qty" class="oe_inline"/>
<field name="product_uom" groups="product.group_uom" class="oe_inline"/>
</div>
<field name="price_unit"/>
</group>
<group>
<field name="taxes_id" widget="many2many_tags" domain="[('type_tax_use', '=', 'purchase')]"/>
<field name="date_planned" widget="date"/>
<field name="account_analytic_id" colspan="2" groups="purchase.group_analytic_accounting"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
</group>
</group>
<notebook>
<page string="Notes">
<field name="name"/>
</page><page string="Invoices and Incoming Shipments">
<field name="invoice_lines"/>
<field name="move_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="purchase_order_line_tree" model="ir.ui.view">
<field name="name">purchase.order.line.tree</field>
<field name="model">purchase.order.line</field>
@@ -506,12 +411,10 @@
<field name="product_uom" groups="product.group_uom"/>
<field name="price_subtotal" widget="monetary"/>
<field name="date_planned" widget="date" width="135"/>
<field name="state" invisible="1"/>
<field name="invoiced" invisible="1"/>
</tree>
</field>
</record>
<record id="purchase_order_line_form2" model="ir.ui.view">
<field name="name">purchase.order.line.form2</field>
<field name="model">purchase.order.line</field>
@@ -521,7 +424,7 @@
<sheet>
<label for="order_id" class="oe_edit_only"/>
<h1>
<field name="order_id" class="oe_inline" domain="[('invoice_method','=','manual')]" />
<field name="order_id" class="oe_inline"/>
<label string="," attrs="{'invisible':[('date_order','=',False)]}"/>
<field name="date_order" class="oe_inline"/>
</h1>
@@ -543,7 +446,6 @@
<field name="date_planned" widget="date" readonly="1"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
<field name="account_analytic_id" colspan="4" groups="purchase.group_analytic_accounting"/>
<field name="invoiced"/>
</group>
</group>
<field name="name"/>
@@ -574,42 +476,6 @@
</field>
</record>
<record id="purchase_line_form_action2" model="ir.actions.act_window">
<field name="name">Purchase Order Lines</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">purchase.order.line</field>
<field name="domain">[('order_id.invoice_method','=','manual'), ('state','in',('confirmed','done')), ('invoiced', '=', False)]</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="purchase_order_line_search"/>
<field name="help" type="html">
<p>
Here you can track all the lines of purchase orders where the
invoicing is "Based on Purchase Order Lines", and for which you
have not received a vendor bill yet. You can generate a
draft vendor bill based on the lines from this list.
</p>
</field>
</record>
<record id="purchase_line_form_action_tree2" model="ir.actions.act_window.view">
<field eval="1" name="sequence"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="purchase_order_line_tree"/>
<field name="act_window_id" ref="purchase_line_form_action2"/>
</record>
<record id="purchase_line_form_action_form2" model="ir.actions.act_window.view">
<field eval="2" name="sequence"/>
<field name="view_mode">form</field>
<field name="view_id" ref="purchase_order_line_form2"/>
<field name="act_window_id" ref="purchase_line_form_action2"/>
</record>
<menuitem
action="purchase_line_form_action2"
id="menu_purchase_line_order_draft"
parent="menu_procurement_management_invoice"
sequence="72"/>
<!-- Procurements -->
<record id="view_procurement_form_inherit" model="ir.ui.view">
@@ -636,6 +502,9 @@
<label for="purchase_ok"/>
</div>
</div>
<field name="uom_po_id" position="after">
<field name="purchase_method" widget="radio" groups="base.group_no_one"/>
</field>
</field>
</record>
@@ -664,7 +533,8 @@
</record>
<record model="ir.actions.act_window" id="action_purchase_line_product_tree">
<field name="context">{}</field><!-- force empty -->
<field name="context">{}</field>
<field name="domain">[('product_id','in',active_ids)]</field>
<field name="name">Purchases</field>
<field name="res_model">purchase.order.line</field>
<field name="view_id" ref="purchase_order_line_tree"/>
@@ -691,25 +561,9 @@
<field name="groups_id" eval="[(4, ref('purchase.group_purchase_user'))]"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<button class="oe_stat_button" name="action_view_purchases" type="object"
icon="fa-shopping-cart"
groups="base.group_no_one">
<field string="Purchases" name="purchase_count" widget="statinfo"/>
</button>
</div>
</field>
</record>
<record id="view_product_normal_purchase_buttons_from" model="ir.ui.view">
<field name="name">product.product.purchase.button.inherit</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="groups_id" eval="[(4, ref('purchase.group_purchase_user'))]"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<button class="oe_stat_button" name="action_view_purchases" type="object"
icon="fa-shopping-cart"
groups="base.group_no_one">
<button class="oe_stat_button" name="%(purchase.action_purchase_line_product_tree)d"
type="action" icon="fa-shopping-cart"
groups="base.group_no_one">
<field string="Purchases" name="purchase_count" widget="statinfo"/>
</button>
</div>
-231
View File
@@ -1,231 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="purchase_order" model="workflow">
<field name="name">Purchase Order Basic Workflow</field>
<field name="osv">purchase.order</field>
<field name="on_create">True</field>
</record>
<record id="act_draft" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="flow_start">True</field>
<field name="name">draft</field>
</record>
<record id="act_sent" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">sent</field>
<field name="kind">function</field>
<field name="action">write({'state':'sent'})</field>
</record>
<record id="act_bid" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">bid</field>
<field name="kind">function</field>
<field name="action">wkf_bid_received()</field>
</record>
<record id="act_confirmed" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">confirmed</field>
<field name="split_mode">OR</field>
<field name="kind">function</field>
<field name="action">wkf_confirm_order()</field>
</record>
<record id="act_cancel" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">cancel</field>
<field name="kind">function</field>
<field name="flow_stop">True</field>
<field name="action">wkf_action_cancel()</field>
</record>
<record id="act_except_invoice" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">except_invoice</field>
<field name="kind">function</field>
<field name="action">write({'state':'except_invoice'})</field>
</record>
<record id="act_except_picking" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">except_picking</field>
<field name="kind">function</field>
<field name="action">write({'state':'except_picking'})</field>
</record>
<record id="act_router" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">router</field>
<field name="split_mode">OR</field>
<field name="kind">function</field>
<field name="join_mode">AND</field>
<field name="action">wkf_approve_order()</field>
</record>
<record id="act_invoice" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">invoice</field>
<field name="kind">subflow</field>
<field name="subflow_id" search="[('osv','=','account.invoice')]"/>
<field name="action">action_invoice_create()</field>
</record>
<record id="act_invoice_done" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">invoice_done</field>
<field name="action">invoice_done()</field>
<field name="kind">function</field>
</record>
<record id="act_invoice_end" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">invoice_end</field>
</record>
<record id="act_picking" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">picking</field>
<field name="kind">function</field>
<field name="action">action_picking_create()</field>
</record>
<record id="act_picking_done" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">picking_done</field>
<field name="action">picking_done()</field>
<field name="kind">function</field>
</record>
<record id="act_done" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
<field name="name">done</field>
<field name="action">wkf_po_done()</field>
<field name="kind">function</field>
<field name="flow_stop">True</field>
<field name="join_mode">AND</field>
</record>
<record id="trans_draft_confirmed" model="workflow.transition">
<field name="act_from" ref="act_draft"/>
<field name="act_to" ref="act_confirmed"/>
<field name="signal">purchase_confirm</field>
</record>
<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">send_rfq</field>
</record>
<record id="trans_bid_confirmed" model="workflow.transition">
<field name="act_from" ref="act_bid"/>
<field name="act_to" ref="act_confirmed"/>
<field name="signal">purchase_confirm</field>
</record>
<record id="trans_sent_bid" model="workflow.transition">
<field name="act_from" ref="act_sent"/>
<field name="act_to" ref="act_bid"/>
<field name="signal">bid_received</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">purchase_cancel</field>
</record>
<record id="trans_bid_cancel" model="workflow.transition">
<field name="act_from" ref="act_bid"/>
<field name="act_to" ref="act_cancel"/>
<field name="signal">purchase_cancel</field>
</record>
<record id="trans_confirmed_cancel" model="workflow.transition">
<field name="act_from" ref="act_confirmed"/>
<field name="act_to" ref="act_cancel"/>
<field name="signal">purchase_cancel</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">purchase_cancel</field>
</record>
<record id="trans_confirmed_router" model="workflow.transition">
<field name="act_from" ref="act_confirmed"/>
<field name="act_to" ref="act_router"/>
<!-- <field name="signal">purchase_approve</field> removed from simplification/useability -->
</record>
<record id="trans_router_picking" model="workflow.transition">
<field name="act_from" ref="act_router"/>
<field name="act_to" ref="act_picking"/>
<field name="condition">has_stockable_product()</field>
</record>
<record id="trans_router_picking_done" model="workflow.transition">
<field name="act_from" ref="act_router"/>
<field name="act_to" ref="act_picking_done"/>
<field name="condition">not has_stockable_product()</field>
</record>
<record id="trans_router_invoice" model="workflow.transition">
<field name="act_from" ref="act_router"/>
<field name="act_to" ref="act_invoice"/>
<field name="condition">invoice_method=='order'</field>
</record>
<record id="trans_router_invoice_no_order" model="workflow.transition">
<field name="act_from" ref="act_router"/>
<field name="act_to" ref="act_invoice_end"/>
<field name="condition">invoice_method&lt;&gt;'order'</field>
</record>
<record id="trans_except_picking_picking_done" model="workflow.transition">
<field name="act_from" ref="act_except_picking"/>
<field name="act_to" ref="act_picking_done"/>
<field name="signal">picking_ok</field>
</record>
<record id="trans_except_invoice_invoice_done" model="workflow.transition">
<field name="act_from" ref="act_except_invoice"/>
<field name="act_to" ref="act_invoice_done"/>
<field name="signal">invoice_ok</field>
</record>
<record id="trans_except_picking" model="workflow.transition">
<field name="act_from" ref="act_except_picking"/>
<field name="act_to" ref="act_cancel"/>
<field name="signal">purchase_cancel</field>
</record>
<record id="trans_except_invoice" model="workflow.transition">
<field name="act_from" ref="act_except_invoice"/>
<field name="act_to" ref="act_cancel"/>
<field name="signal">purchase_cancel</field>
</record>
<record id="trans_picking_except_picking" model="workflow.transition">
<field name="act_from" ref="act_picking"/>
<field name="act_to" ref="act_except_picking"/>
<field name="signal">picking_cancel</field>
</record>
<record id="trans_invoice_except_invoice" model="workflow.transition">
<field name="act_from" ref="act_invoice"/>
<field name="act_to" ref="act_except_invoice"/>
<field name="signal">subflow.cancel</field>
</record>
<record id="trans_picking_picking_done" model="workflow.transition">
<field name="act_from" ref="act_picking"/>
<field name="act_to" ref="act_picking_done"/>
<field name="signal">picking_done</field>
</record>
<record id="trans_invoice_invoice_done" model="workflow.transition">
<field name="act_from" ref="act_invoice"/>
<field name="act_to" ref="act_invoice_done"/>
<field name="signal">subflow.paid</field>
</record>
<record id="trans_picking_done_done" model="workflow.transition">
<field name="act_from" ref="act_picking_done"/>
<field name="act_to" ref="act_done"/>
</record>
<record id="trans_invoice_done_done" model="workflow.transition">
<field name="act_from" ref="act_invoice_done"/>
<field name="act_to" ref="act_invoice_end"/>
</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"/>
<field name="condition">invoiced</field>
</record>
<record id="trans_invoice_end_cancel" model="workflow.transition">
<field name="act_from" ref="act_invoice_end"/>
<field name="act_to" ref="act_cancel"/>
<field name="signal">purchase_cancel</field>
<field name="condition">invoice_method&lt;&gt;'order'</field>
</record>
</data>
</openerp>
+9 -18
View File
@@ -14,20 +14,17 @@ class purchase_report(osv.osv):
_auto = False
_columns = {
'date': fields.datetime('Order Date', readonly=True, help="Date on which this document has been created"), # TDE FIXME master: rename into date_order
'state': fields.selection([('draft', 'Request for Quotation'),
('confirmed', 'Waiting Vendor Ack'),
('approved', 'Approved'),
('except_picking', 'Shipping Exception'),
('except_invoice', 'Invoice Exception'),
('done', 'Done'),
('cancel', 'Cancelled')],'Order Status', readonly=True),
'state': fields.selection([('draft', 'Draft RFQ'),
('sent', 'RFQ Sent'),
('to approve', 'To Approve'),
('purchase', 'Purchase Order'),
('done', 'Done'),
('cancel', 'Cancelled')
],'Order Status', readonly=True),
'product_id':fields.many2one('product.product', 'Product', readonly=True),
'picking_type_id': fields.many2one('stock.warehouse', 'Warehouse', readonly=True),
'location_id': fields.many2one('stock.location', 'Destination', readonly=True),
'partner_id':fields.many2one('res.partner', 'Vendor', readonly=True),
'date_approve':fields.date('Date Approved', readonly=True),
'expected_date':fields.date('Expected Date', readonly=True),
'validator' : fields.many2one('res.users', 'Validated By', readonly=True),
'product_uom' : fields.many2one('product.uom', 'Reference Unit of Measure', required=True),
'company_id':fields.many2one('res.company', 'Company', readonly=True),
'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
@@ -64,11 +61,9 @@ class purchase_report(osv.osv):
select
min(l.id) as id,
s.date_order as date,
l.state,
s.state,
s.date_approve,
s.minimum_planned_date as expected_date,
s.dest_address_id,
s.validator,
spt.warehouse_id as picking_type_id,
s.partner_id as partner_id,
s.create_uid as user_id,
@@ -78,7 +73,6 @@ class purchase_report(osv.osv):
p.product_tmpl_id,
t.categ_id as category_id,
t.uom_id as product_uom,
s.location_id as location_id,
sum(l.product_qty/u.factor*u2.factor) as quantity,
extract(epoch from age(s.date_approve,s.date_order))/(24*60*60)::decimal(16,2) as delay,
extract(epoch from age(l.date_planned,s.date_order))/(24*60*60)::decimal(16,2) as delay_pass,
@@ -108,20 +102,17 @@ class purchase_report(osv.osv):
s.create_uid,
s.partner_id,
u.factor,
s.location_id,
l.price_unit,
s.date_approve,
l.date_planned,
l.product_uom,
s.minimum_planned_date,
s.validator,
s.dest_address_id,
s.fiscal_position_id,
l.product_id,
p.product_tmpl_id,
t.categ_id,
s.date_order,
l.state,
s.state,
spt.warehouse_id,
u.uom_type,
u.category_id,
@@ -61,13 +61,10 @@
<field name="product_id"/>
<group expand="0" string="Extended Filters">
<field name="user_id"/>
<field name="validator"/>
<field name="location_id"/>
<field name="picking_type_id"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="date"/>
<field name="date_approve"/>
<field name="expected_date"/>
</group>
<group expand="1" string="Group By">
<filter string="Vendor" name="group_partner_id" context="{'group_by':'partner_id'}"/>
-9
View File
@@ -15,11 +15,6 @@ class purchase_config_settings(osv.osv_memory):
], "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'),
'default_invoice_method': fields.selection(
[('manual', 'Control vendor bill on purchase order line'),
('picking', 'Control vendor bill on incoming shipments'),
('order', 'Control vendor bill on a pregenerated draft invoice'),
], 'Default invoicing control method', required=True, default_model='purchase.order'),
'group_uom':fields.selection([
(0, 'Products have only one unit of measure (easier)'),
(1, 'Some products may be sold/puchased in different unit of measures (advanced)')
@@ -53,10 +48,6 @@ class purchase_config_settings(osv.osv_memory):
'-This installs the module stock_dropshipping.'),
}
_defaults = {
'default_invoice_method': 'order',
}
class account_config_settings(osv.osv_memory):
_inherit = 'account.config.settings'
-6
View File
@@ -22,12 +22,6 @@
<button string="Apply" type="object" name="execute" class="oe_highlight"/>
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
</header>
<group string="Invoicing Process">
<label for="id" string="Default Invoicing Settings"/>
<div>
<field name="default_invoice_method" widget="radio"/>
</div>
</group>
<group string="Purchase Order">
<field name="group_product_variant" widget="radio"/>
<field name="group_uom" widget="radio"/>
+8 -141
View File
@@ -6,6 +6,14 @@ from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp.exceptions import UserError
class stock_picking(osv.osv):
_inherit = 'stock.picking'
_columns = {
'purchase_id': fields.related('move_lines', 'purchase_line_id', 'order_id', string="Purchase Orders",
readonly=True, relation="many2one"),
}
class stock_move(osv.osv):
_inherit = 'stock.move'
_columns = {
@@ -18,34 +26,8 @@ class stock_move(osv.osv):
""" Returns the unit price to store on the quant """
if move.purchase_line_id:
return move.price_unit
return super(stock_move, self).get_price_unit(cr, uid, move, context=context)
def write(self, cr, uid, ids, vals, context=None):
if isinstance(ids, (int, long)):
ids = [ids]
res = super(stock_move, self).write(cr, uid, ids, vals, context=context)
from openerp import workflow
if vals.get('state') in ['done', 'cancel']:
po_to_check = []
for move in self.browse(cr, uid, ids, context=context):
if move.purchase_line_id and move.purchase_line_id.order_id:
order = move.purchase_line_id.order_id
order_id = order.id
# update linked purchase order as superuser as the warehouse
# user may not have rights to access purchase.order
if self.pool.get('purchase.order').test_moves_done(cr, uid, [order_id], context=context):
workflow.trg_validate(SUPERUSER_ID, 'purchase.order', order_id, 'picking_done', cr)
if self.pool.get('purchase.order').test_moves_except(cr, uid, [order_id], context=context):
workflow.trg_validate(SUPERUSER_ID, 'purchase.order', order_id, 'picking_cancel', cr)
if order_id not in po_to_check and vals['state'] == 'cancel' and order.invoice_method == 'picking':
po_to_check.append(order_id)
# Some moves which are cancelled might be part of a PO line which is partially
# invoiced, so we check if some PO line can be set on "invoiced = True".
if po_to_check:
self.pool.get('purchase.order')._set_po_lines_invoiced(cr, uid, po_to_check, context=context)
return res
def copy(self, cr, uid, id, default=None, context=None):
default = default or {}
context = context or {}
@@ -54,121 +36,6 @@ class stock_move(osv.osv):
default['purchase_line_id'] = False
return super(stock_move, self).copy(cr, uid, id, default, context)
def _get_master_data(self, cr, uid, move, inv_type, context=None):
if inv_type == 'in_invoice' and move.purchase_line_id:
purchase_order = move.purchase_line_id.order_id
return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.currency_id.id
if inv_type == 'in_refund' and move.origin_returned_move_id.purchase_line_id:
purchase_order = move.origin_returned_move_id.purchase_line_id.order_id
return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.currency_id.id
elif inv_type in ('in_invoice', 'in_refund') and move.picking_id:
# In case of an extra move, it is better to use the data from the original moves
for purchase_move in move.picking_id.move_lines:
if purchase_move.purchase_line_id:
purchase_order = purchase_move.purchase_line_id.order_id
return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.currency_id.id
partner = move.picking_id and move.picking_id.partner_id or False
code = self.get_code_from_locs(cr, uid, move, context=context)
if partner and code == 'incoming':
currency = purchase_order.currency_id.id
return partner, uid, currency
return super(stock_move, self)._get_master_data(cr, uid, move, inv_type, context=context)
def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None):
res = super(stock_move, self)._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context)
purchase_line = False
if inv_type == 'in_invoice' and move.purchase_line_id:
purchase_line = move.purchase_line_id
elif inv_type == 'in_refund' and move.origin_returned_move_id.purchase_line_id:
purchase_line = move.origin_returned_move_id.purchase_line_id
if purchase_line:
res['invoice_line_tax_ids'] = [(6, 0, [x.id for x in purchase_line.taxes_id])]
res['price_unit'] = purchase_line.price_unit
res['account_analytic_id'] = purchase_line.account_analytic_id.id
res['purchase_line_ids'] = [(4, purchase_line.id)]
return res
def _get_moves_taxes(self, cr, uid, moves, inv_type, context=None):
is_extra_move, extra_move_tax = super(stock_move, self)._get_moves_taxes(cr, uid, moves, inv_type, context=context)
if inv_type == 'in_invoice':
for move in moves:
if move.purchase_line_id:
is_extra_move[move.id] = False
extra_move_tax[move.picking_id, move.product_id] = [(6, 0, [x.id for x in move.purchase_line_id.taxes_id])]
elif move.product_id.product_tmpl_id.supplier_taxes_id:
mov_id = self.search(cr, uid, [('purchase_line_id', '!=', False), ('picking_id', '=', move.picking_id.id)], limit=1, context=context)
if mov_id:
mov = self.browse(cr, uid, mov_id[0], context=context)
fp = mov.purchase_line_id.order_id.fiscal_position
res = self.pool.get("account.invoice.line").product_id_change(cr, uid, [], move.product_id.id, None, partner_id=move.picking_id.partner_id.id, fposition_id=(fp and fp.id), type='in_invoice', context=context)
extra_move_tax[0, move.product_id] = [(6, 0, res['value']['invoice_line_tax_ids'])]
return (is_extra_move, extra_move_tax)
def _get_taxes(self, cr, uid, move, context=None):
if move.origin_returned_move_id.purchase_line_id.taxes_id:
return [tax.id for tax in move.origin_returned_move_id.purchase_line_id.taxes_id]
return super(stock_move, self)._get_taxes(cr, uid, move, context=context)
class stock_picking(osv.osv):
_inherit = 'stock.picking'
def _get_to_invoice(self, cr, uid, ids, name, args, context=None):
res = {}
for picking in self.browse(cr, uid, ids, context=context):
res[picking.id] = False
for move in picking.move_lines:
if move.purchase_line_id and move.purchase_line_id.order_id.invoice_method == 'picking':
if not move.move_orig_ids:
res[picking.id] = True
return res
def _get_picking_to_recompute(self, cr, uid, ids, context=None):
picking_ids = set()
for move in self.pool.get('stock.move').browse(cr, uid, ids, context=context):
if move.picking_id and move.purchase_line_id:
picking_ids.add(move.picking_id.id)
return list(picking_ids)
_columns = {
'reception_to_invoice': fields.function(_get_to_invoice, type='boolean', string='Invoiceable on incoming shipment',
help='Does the picking contain some moves related to a purchase order invoiceable on the receipt?',
store={
'stock.move': (_get_picking_to_recompute, ['purchase_line_id', 'picking_id'], 10),
}),
}
def _get_invoice_vals(self, cr, uid, key, inv_type, journal_id, moves, context=None):
inv_vals = super(stock_picking, self)._get_invoice_vals(cr, uid, key, inv_type, journal_id, moves, context=context)
purchases = []
for move in moves:
if move.purchase_line_id or move.origin_returned_move_id.purchase_line_id:
purchase = move.purchase_line_id.order_id or move.origin_returned_move_id.purchase_line_id.order_id
inv_vals.update({
'fiscal_position_id': purchase.fiscal_position_id.id,
'payment_term_id': purchase.payment_term_id.id,
})
purchases.append(purchase.id)
if purchases:
inv_vals['purchase_ids'] = [(6, 0, list(set(purchases)))]
return inv_vals
def get_service_line_vals(self, cr, uid, moves, partner, inv_type, context=None):
purchase_obj = self.pool['purchase.order']
purchase_line_obj = self.pool['purchase.order.line']
res = super(stock_picking, self).get_service_line_vals(cr, uid, moves, partner, inv_type, context=context)
# Add service lines for purchases
if inv_type == 'in_invoice':
purchase_ids = list(set([x.purchase_line_id.order_id.id for x in moves if x.purchase_line_id]))
purchase_line_ids = purchase_line_obj.search(cr, uid, [('order_id', 'in', purchase_ids), ('invoice_lines', '=', False), '|', ('product_id', '=', False),
('product_id.type', '=', 'service')], context=context)
for po_line in purchase_line_obj.browse(cr, uid, purchase_line_ids, context=context):
acc_id = purchase_obj._choose_account_from_po_line(cr, uid, po_line, context=context)
inv_line_data = purchase_obj._prepare_inv_line(cr, uid, acc_id, po_line, context=context)
inv_line_data['purchase_line_ids'] = [(4, po_line.id)]
res += [(0, 0, inv_line_data)]
return res
class stock_warehouse(osv.osv):
_inherit = 'stock.warehouse'
-49
View File
@@ -23,32 +23,6 @@
</field>
</record>
<!-- is it need ? we have another method "Receive Products"-->
<record id="purchase_order_2_stock_picking" model="ir.ui.view">
<field name="name">Purchase Picking Inherited</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<xpath expr="//div[contains(@class, 'oe_title')]" position="before">
<div class="oe_button_box" name="button_box">
<button type="object"
name="view_picking"
class="oe_stat_button"
icon="fa-truck"
attrs="{'invisible': [('shipment_count', '=', 0)]}">
<field name="shipment_count" widget="statinfo" string="Shipment" help="Incoming Shipments"/>
</button>
<button type="object" name="invoice_open"
class="oe_stat_button"
icon="fa-pencil-square-o"
attrs="{'invisible': [('invoice_count', '=', 0)]}">
<field name="invoice_count" widget="statinfo" string="Invoices"/>
</button>
</div>
</xpath>
</field>
</record>
<record id="view_warehouse_inherited" model="ir.ui.view">
<field name="name">Stock Warehouse Inherited</field>
<field name="model">stock.warehouse</field>
@@ -60,28 +34,5 @@
</field>
</record>
<record id="action_picking_tree_picking_to_invoice" model="ir.actions.act_window">
<field name="name">Incoming Shipments</field>
<field name="res_model">stock.picking</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar</field>
<field name="context">{"default_type": "in", "contact_display": "partner_address", "search_default_done": 1, "search_default_reception_to_invoice": 1}</field>
<field name="search_view_id" ref="stock.view_picking_internal_search"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new incoming shipment.
</p><p>
Here you can track all the product receipts of purchase
orders where the invoicing is "Based on Incoming Shipments",
and for which you have not received a supplier bill yet.
You can generate a supplier bill based on those receipts.
</p>
</field>
</record>
<menuitem action="action_picking_tree_picking_to_invoice"
id="menu_action_picking_tree_picking_to_invoice"
parent="purchase.menu_procurement_management_invoice" sequence="90"/>
</data>
</openerp>
-247
View File
@@ -1,247 +0,0 @@
-
I first set the company to use anglo saxon accounting.
-
!python {model: res.company}: |
self.pool.get('res.company').write(cr, uid, ref("base.main_company"), {'anglo_saxon_accounting': True,})
-
In order to test anglo_saxon Configure Different Accounts.
-
!record {model: account.account, id: account_anglo_stock_valuation}:
code: X3000
name: Stock Valuation Account- (test)
user_type_id: account.data_account_type_current_assets
-
Configure Stock Interim account (Received).
-
!record {model: account.account, id: account_anglo_stock_input}:
code: X2800
name: Stock Interim account (Received)
user_type_id: account.data_account_type_expenses
-
Configure Stock Interim account (Delivered).
-
!record {model: account.account, id: account_anglo_stock_output}:
code: X2801
name: Stock Interim account (Delivered)
user_type_id: account.data_account_type_revenue
-
Configure Price difference creditor Account.
-
!record {model: account.account, id: account_anglo_price_difference}:
code: X7095
name: Price difference creditor Account
user_type_id: account.data_account_type_expenses
-
Configure Cash Bank Account.
-
!record {model: account.account, id: account_anglo_cash}:
code: X5000
name: Cash/Bank Account
user_type_id: account.data_account_type_liquidity
reconcile: True
-
Configure Creditor Account Payable.
-
!record {model: account.account, id: account_anglo_payable}:
code: X440001
name: Creditor Account Payable
user_type_id: account.data_account_type_payable
reconcile: True
-
Configure Debtor Account Receivable.
-
!record {model: account.account, id: account_anglo_receivable}:
code: X400001
name: Debtor Account Receivable
user_type_id: account.data_account_type_receivable
reconcile: True
-
Configure Cost of Good sale Account.
-
!record {model: account.account, id: account_anglo_cogs}:
code: X7000
name: Cost of goods sale account
user_type_id: account.data_account_type_expenses
-
Configure Income Account.
-
!record {model: account.account, id: account_anglo_income}:
code: X8000
name: Income Account
user_type_id: account.data_account_type_revenue
-
I configure the account receivable of supplier
-
!record {model: res.partner, id: base.res_partner_3}:
property_account_payable_id: account_anglo_payable
property_account_receivable_id: account_anglo_receivable
-
I configure the account receivable of Customer.
-
!record {model: res.partner, id: base.res_partner_2}:
property_account_payable_id: account_anglo_payable
property_account_receivable_id: account_anglo_receivable
-
I configure the product category with stock valuation account.
-
!record {model: product.category, id: product.product_category_5}:
property_stock_valuation_account_id: account_anglo_stock_valuation
-
I configure the product with required accounts, and cost method = standard
-
!python {model: product.product}: |
self.write(cr, uid, [ref('product.product_product_10')], {'list_price': 20.00,'standard_price': 9,'categ_id': ref('product.product_category_5'),'valuation': 'real_time',
'property_account_income_id': ref('account_anglo_income'),'property_account_expense_id': ref('account_anglo_cogs'),
'property_account_creditor_price_difference': ref('account_anglo_price_difference'),'property_stock_account_input': ref('account_anglo_stock_input'),
'property_stock_account_output': ref('account_anglo_stock_output'), 'cost_method': 'standard'})
-
I create a draft Purchase Order.
-
!record {model: purchase.order, id: purchase_order_001}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product.product_product_10
product_qty: 1
price_unit: 10
date_planned: !eval "'%s' % (time.strftime('%Y-%m-%d'))"
-
I confirm the purchase order.
-
!workflow {model: purchase.order, ref: purchase_order_001, action: purchase_confirm}
-
Receipt is ready for process so now we do it.
-
!python {model: stock.picking}: |
picking_id = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_001"), context=context).picking_ids[0]
picking_id.do_transfer()
-
I check the Stock Interim account (Received) is credited successfully.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to credit field is removed
# credit = self.browse(cr, uid, ref('account_anglo_stock_input')).credit
# float_compare(credit, 9, precision_digits=2) == 0, "Stock Interim account (Received) is not credited successfully."
-
I check the Stock valuation account is debited sucessfully.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to debit field is removed
# debit = self.browse(cr, uid, ref('account_anglo_stock_valuation')).debit
# float_compare(debit, 9, precision_digits=2) == 0, "Stock valuation account is not debited successfully."
-
I Validate Invoice of Purchase Order.
-
!python {model: purchase.order}: |
invoice_ids = [x.id for x in self.browse(cr, uid, ref("purchase_order_001")).invoice_ids]
self.pool.get('account.invoice').signal_workflow(cr, uid, invoice_ids, 'invoice_open')
-
I check the Stock Interim account (Received) is debited sucessfully when Invoice validated.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to debit field is removed
# debit = self.browse(cr, uid, ref('account_anglo_stock_input')).debit
# float_compare(debit, 9, precision_digits=2) == 0, "Stock Interim account (Received) is not debited successfully."
-
I check the Price difference creditor Account is debited sucessfully when Invoice validated.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to debit field is removed
# debit = self.browse(cr, uid, ref('account_anglo_price_difference')).debit
# float_compare(debit, 1, precision_digits=2) == 0, "Price difference creditor Account is not debited successfully."
-
I check Payable(creditor) Account is Credited sucessfully when Invoice validated.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to credit field is removed
# credit = self.browse(cr, uid, ref('account_anglo_payable')).credit
# float_compare(credit, 10, precision_digits=2) == 0, "Payable(creditor) Account is not Credited successfully."
-
I open the Invoice.
-
!python {model: purchase.order}: |
po = self.browse(cr, uid, ref("purchase_order_001"))
for invoice in po.invoice_ids:
invoice.signal_workflow('invoice_open')
-
I pay the invoice.
-
!python {model: purchase.order}: |
invoice_ids = self.browse(cr, uid, ref("purchase_order_001")).invoice_ids
order = self.browse(cr, uid, ref("purchase_order_001"))
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 invoice_ids:
self.pool.get('account.invoice').pay_and_reconcile(cr, uid, [invoice.id], journal_ids[0])
-
I check Payable(Creditors) Account is Debited sucessfully after invoice paid.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to debit field is removed
# debit = self.browse(cr, uid, ref('account_anglo_payable')).debit
# assert float_compare(debit, 10, precision_digits=2) == 0, "Payable(Creditors) Account is not Debited successfully."
-
I check Bank/Cash account is credited sucessfully after invoice paid.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to credit field is removed
# credit = self.browse(cr, uid, ref('account_anglo_cash')).credit
# float_compare(credit, 10, precision_digits=2) == 0, "Bank/Cash account is not credited successfully."
-
I create an Outgoing Picking order
-
!record {model: stock.picking, id: stock_picking_out001}:
partner_id: base.res_partner_2
move_lines:
- company_id: base.main_company
location_id: stock.stock_location_stock
product_id: product.product_product_10
product_uom_qty: 1.0
product_uom: product.product_uom_unit
location_dest_id: stock.stock_location_customers
move_type: direct
picking_type_id: stock.picking_type_out
-
I need to check the availability of the product, So I make my picking order for processing later.
-
!python {model: stock.picking}: |
self.action_confirm(cr, uid, [ref('stock_picking_out001')], context=context)
-
I check the product availability, Product is available in the stock and ready to be sent.
-
!python {model: stock.picking}: |
picking = self.browse(cr, uid, ref("stock_picking_out001"))
assert picking.state == "confirmed", "Picking should be confirmed."
for move_line in picking.move_lines:
assert move_line.state == "confirmed", "Move should be confirmed."
-
I process the delivery.
-
!python {model: stock.picking}: |
picking = self.pool.get('stock.picking').browse(cr, uid, ref("stock_picking_out001"), context=context)
picking.do_transfer()
-
I check Stock Interim account (Delivery) is debited successfully.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to debit field is removed
# debit = self.browse(cr, uid, ref('account_anglo_stock_output')).debit
# float_compare(debit, 9, precision_digits=2) == 0, "Stock Interim account (Delivery) is not debited successfully."
-
I check the Stock valuation account is credited sucessfully.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to credit field is removed
# credit = self.browse(cr, uid, ref('account_anglo_stock_valuation')).credit
# float_compare(credit, 9, precision_digits=2) == 0, "Stock valuation account is not credited successfully."
@@ -1,247 +0,0 @@
-
I first set the company to use anglo saxon accounting.
-
!python {model: res.company}: |
self.pool.get('res.company').write(cr, uid, ref("base.main_company"), {'anglo_saxon_accounting': True,})
-
In order to test anglo_saxon Configure Different Accounts.
-
!record {model: account.account, id: account_anglo_stock_valuation_fifo}:
code: X3000f
name: Stock Valuation Account- (test)
user_type_id: account.data_account_type_current_assets
-
Configure Stock Interim account (Received).
-
!record {model: account.account, id: account_anglo_stock_input_fifo}:
code: X2800f
name: Stock Interim account (Received)
user_type_id: account.data_account_type_expenses
-
Configure Stock Interim account (Delivered).
-
!record {model: account.account, id: account_anglo_stock_output_fifo}:
code: X2801f
name: Stock Interim account (Delivered)
user_type_id: account.data_account_type_revenue
-
Configure Price difference creditor Account.
-
!record {model: account.account, id: account_anglo_price_difference_fifo}:
code: X7095f
name: Price difference creditor Account
user_type_id: account.data_account_type_expenses
-
Configure Cash Bank Account.
-
!record {model: account.account, id: account_anglo_cash_fifo}:
code: X5000f
name: Cash/Bank Account
user_type_id: account.data_account_type_liquidity
reconcile: True
-
Configure Creditor Account Payable.
-
!record {model: account.account, id: account_anglo_payable_fifo}:
code: X440001f
name: Creditor Account Payable
user_type_id: account.data_account_type_payable
reconcile: True
-
Configure Debtor Account Receivable.
-
!record {model: account.account, id: account_anglo_receivable_fifo}:
code: X400001f
name: Debtor Account Receivable
user_type_id: account.data_account_type_receivable
reconcile: True
-
Configure Cost of Good sale Account.
-
!record {model: account.account, id: account_anglo_cogs_fifo}:
code: X7000f
name: Cost of goods sale account
user_type_id: account.data_account_type_expenses
-
Configure Income Account.
-
!record {model: account.account, id: account_anglo_income_fifo}:
code: X8000f
name: Income Account
user_type_id: account.data_account_type_revenue
-
I configure the account receivable of supplier
-
!record {model: res.partner, id: base.res_partner_3}:
property_account_payable_id: account_anglo_payable_fifo
property_account_receivable_id: account_anglo_receivable_fifo
-
I configure the account receivable of Customer.
-
!record {model: res.partner, id: base.res_partner_2}:
property_account_payable_id: account_anglo_payable_fifo
property_account_receivable_id: account_anglo_receivable_fifo
-
I configure the product category with stock valuation account.
-
!record {model: product.category, id: product.product_category_5}:
property_stock_valuation_account_id: account_anglo_stock_valuation_fifo
-
I create a product with required accounts, and cost method average (but same applies for fifo)
-
!record {model: product.product, id: product_fifo_anglo_saxon}:
name: 'FIFO product for anglo saxon tests'
lst_price: 20.00
standard_price: 0
categ_id: product.product_category_5
valuation: 'real_time'
property_account_income_id: account_anglo_income_fifo
property_account_expense_id: account_anglo_cogs_fifo
property_account_creditor_price_difference: account_anglo_price_difference_fifo
property_stock_account_input: account_anglo_stock_input_fifo
property_stock_account_output: account_anglo_stock_output_fifo
cost_method: 'average'
-
I create a draft Purchase Order.
-
!record {model: purchase.order, id: purchase_order_001_fifo}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_fifo_anglo_saxon
product_qty: 1
price_unit: 9
date_planned: !eval "'%s' % (time.strftime('%Y-%m-%d'))"
taxes_id: []
-
I confirm the purchase order.
-
!workflow {model: purchase.order, ref: purchase_order_001_fifo, action: purchase_confirm}
-
Receipt is ready for process so now we do it.
-
!python {model: stock.picking}: |
picking_id = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_001_fifo"), context=context).picking_ids[0]
picking_id.do_transfer()
-
I check the Stock Interim account (Received) is credit successfully.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to credit field is removed
# credit = self.browse(cr, uid, ref('account_anglo_stock_input_fifo')).credit
# assert float_compare(credit, 9, precision_digits=2) == 0, "Stock Interim account (Received) is not credited successfully."
-
I check the Stock valuation account is debit sucessfully.
-
!python {model: account.account, id}: |
from openerp.tools import float_compare
# Due to debit field is removed
# debit = self.browse(cr, uid, ref('account_anglo_stock_valuation_fifo')).debit
# assert float_compare(debit, 9, precision_digits=2) == 0, "Stock valuation account is not debited successfully."
-
I Validate Invoice of Purchase Order after having changed the price to 10.
-
!python {model: purchase.order}: |
invoice_ids = [x.id for x in self.browse(cr, uid, ref("purchase_order_001_fifo")).invoice_ids]
line_ids = self.pool.get('account.invoice.line').search(cr, uid, [('invoice_id', 'in', invoice_ids)])
self.pool.get('account.invoice.line').write(cr, uid, line_ids, {'price_unit': 10})
self.pool.get('account.invoice').signal_workflow(cr, uid, invoice_ids, 'invoice_open')
-
I check the Stock Interim account (Received) is debited sucessfully when Invoice validated.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to debit field is removed
# debit = self.browse(cr, uid, ref('account_anglo_stock_input_fifo')).debit
# assert float_compare(debit, 9, precision_digits=2) == 0, "Stock Interim account (Received) is not debited successfully."
-
I check the Price difference creditor Account is debited sucessfully when Invoice validated.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to debit field is removed
# debit = self.browse(cr, uid, ref('account_anglo_price_difference_fifo')).debit
# assert float_compare(debit, 1, precision_digits=2) == 0, "Price difference creditor Account is not debited successfully."
-
I check Payable(creditor) Account is Credited sucessfully when Invoice validated.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to credit field is removed
# credit = self.browse(cr, uid, ref('account_anglo_payable_fifo')).credit
# assert float_compare(credit, 10, precision_digits=2) == 0, "Payable(creditor) Account is not Credited successfully."
-
I pay the invoice.
-
!python {model: purchase.order}: |
invoice_ids = self.browse(cr, uid, ref("purchase_order_001_fifo")).invoice_ids
order = self.browse(cr, uid, ref("purchase_order_001_fifo"))
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 invoice_ids:
self.pool.get('account.invoice').pay_and_reconcile(cr, uid, [invoice.id], journal_ids[0])
-
I check Payable(Creditors) Account is Debited sucessfully after invoice paid.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to debit field is removed
# debit = self.browse(cr, uid, ref('account_anglo_payable_fifo')).debit
# assert float_compare(debit, 10, precision_digits=2) == 0, "Payable(Creditors) Account is not Debited successfully."
-
I check Bank/Cash account is credited sucessfully after invoice paid.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to debit field is removed
# credit = self.browse(cr, uid, ref('account_anglo_cash_fifo')).credit
# assert float_compare(credit, 10, precision_digits=2) == 0, "Bank/Cash account is not credited successfully."
-
I create an Outgoing Picking order
-
!record {model: stock.picking, id: stock_picking_out001_fifo}:
partner_id: base.res_partner_2
move_lines:
- company_id: base.main_company
location_id: stock.stock_location_stock
product_id: product_fifo_anglo_saxon
product_uom_qty: 1.0
location_dest_id: stock.stock_location_customers
move_type: direct
picking_type_id: stock.picking_type_out
-
I need to check the availability of the product, So I make my picking order for processing later.
-
!python {model: stock.picking}: |
self.action_confirm(cr, uid, [ref('stock_picking_out001_fifo')], context=context)
-
I check the product availability, Product is available in the stock and ready to be sent.
-
!python {model: stock.picking}: |
picking = self.browse(cr, uid, ref("stock_picking_out001_fifo"))
assert picking.state == "confirmed", "Picking should be confirmed."
for move_line in picking.move_lines:
assert move_line.state == "confirmed", "Move should be confirmed."
-
I process the delivery.
-
!python {model: stock.picking}: |
picking = self.pool.get('stock.picking').browse(cr, uid, ref("stock_picking_out001_fifo"), context=context)
picking.do_transfer()
-
I check Stock Interim account (Delivery) is debited successfully.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to debit field is removed
# debit = self.browse(cr, uid, ref('account_anglo_stock_output_fifo')).debit
# assert float_compare(debit, 9, precision_digits=2) == 0, "Stock Interim account (Delivery) is not debited successfully."
-
I check the Stock valuation account is credited sucessfully.
-
!python {model: account.account}: |
from openerp.tools import float_compare
# Due to credit field is removed
# credit = self.browse(cr, uid, ref('account_anglo_stock_valuation_fifo')).credit
# assert float_compare(credit, 9, precision_digits=2) == 0, "Stock valuation account is not credited successfully."
+7 -7
View File
@@ -18,7 +18,6 @@
-
!record {model: purchase.order, id: purchase_order_average1}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_average_icecream
product_qty: 10.0
@@ -28,12 +27,13 @@
-
I confirm the first purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_average1}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_average1")])
-
I check the "Approved" status of purchase order 1
-
!assert {model: purchase.order, id: purchase_order_average1}:
- state == 'approved'
- state == 'purchase'
-
Process the reception of purchase order 1
-
@@ -52,7 +52,6 @@
-
!record {model: purchase.order, id: purchase_order_average2}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_average_icecream
product_qty: 30.0
@@ -62,7 +61,8 @@
-
I confirm the second purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_average2}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_average2")])
-
Process the reception of purchase order 2
-
@@ -106,7 +106,6 @@
-
!record {model: purchase.order, id: purchase_order_average3}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_average_icecream
product_qty: 500.0
@@ -116,7 +115,8 @@
-
I confirm the first purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_average3}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_average3")])
-
Process the reception of purchase order 3 in grams
-
+7 -7
View File
@@ -19,7 +19,6 @@
-
!record {model: purchase.order, id: purchase_order_variable1}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_variable_icecream
product_qty: 10.0
@@ -31,7 +30,6 @@
-
!record {model: purchase.order, id: purchase_order_variable2}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_variable_icecream
product_qty: 30.0
@@ -41,16 +39,18 @@
-
I confirm the first purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_variable1}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_variable1")])
-
I confirm the second purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_variable2}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_variable2")])
-
I check the "Approved" status of purchase order 1
-
!assert {model: purchase.order, id: purchase_order_variable1}:
- state == 'approved'
- state == 'purchase'
-
Process the reception of purchase order 1
-
@@ -113,7 +113,6 @@
-
!record {model: purchase.order, id: purchase_order_variable3}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_variable_icecream
product_qty: 20.0
@@ -123,7 +122,8 @@
-
I confirm this third purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_variable3}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_variable3")])
-
Process the reception of purchase order 3
-
+14 -14
View File
@@ -26,7 +26,6 @@
!record {model: purchase.order, id: purchase_order_fifo1}:
partner_id: base.res_partner_3
currency_id: base.EUR
location_id: stock.stock_location_stock
order_line:
- product_id: product_fifo_icecream
product_qty: 10.0
@@ -36,12 +35,13 @@
-
I confirm the first purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_fifo1}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_fifo1")])
-
I check the "Approved" status of purchase order 1
I check the "Purchase" status of purchase order 1
-
!assert {model: purchase.order, id: purchase_order_fifo1}:
- state == 'approved'
- state == 'purchase'
-
Process the reception of purchase order 1 and set date
-
@@ -58,7 +58,6 @@
-
!record {model: purchase.order, id: purchase_order_fifo2}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_fifo_icecream
product_qty: 30.0
@@ -68,7 +67,8 @@
-
I confirm the second purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_fifo2}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_fifo2")])
-
Process the reception of purchase order 2
-
@@ -160,7 +160,6 @@
!record {model: purchase.order, id: purchase_order_fifo_usd}:
partner_id: base.res_partner_3
currency_id: new_USD
location_id: stock.stock_location_stock
order_line:
- product_id: product_fifo_icecream
product_qty: 30000
@@ -174,7 +173,8 @@
-
I confirm the purchase order in USD
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_fifo_usd}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_fifo_usd")])
-
Process the reception of purchase order with usd
-
@@ -202,7 +202,7 @@
-
!python {model: stock.picking}: |
self.action_assign(cr, uid, [ref("outgoing_fifo_shipment_cur")])
-
-
Process the delivery of the outgoing shipment
-
!python {model: stock.picking}: |
@@ -218,7 +218,7 @@
-
!record {model: stock.picking, id: outgoing_fifo_shipment_ret}:
picking_type_id: stock.picking_type_out
-
-
Picking needs movement from stock
-
!record {model: stock.move, id: outgoing_shipment_fifo_icecream_ret}:
@@ -320,7 +320,6 @@
-
!record {model: purchase.order, id: purchase_order_fifo_neg}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_fifo_negative
product_qty: 50.0
@@ -330,7 +329,8 @@
-
I confirm the first purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_fifo_neg}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_fifo_neg")])
-
Process the reception of purchase order 1
-
@@ -348,7 +348,6 @@
-
!record {model: purchase.order, id: purchase_order_fifo_neg2}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_fifo_negative
product_qty: 60.0
@@ -358,7 +357,8 @@
-
I confirm the second negative purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_fifo_neg2}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_fifo_neg2")])
-
Process the reception of purchase order 2
-
+4 -4
View File
@@ -19,7 +19,6 @@
-
!record {model: purchase.order, id: purchase_order_fiforet1}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_fiforet_icecream
product_qty: 10.0
@@ -31,7 +30,6 @@
-
!record {model: purchase.order, id: purchase_order_fiforet2}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
order_line:
- product_id: product_fiforet_icecream
product_qty: 30.0
@@ -41,7 +39,8 @@
-
I confirm the first purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_fiforet1}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_fiforet1")])
-
Process the reception of purchase order 1
-
@@ -56,7 +55,8 @@
-
I confirm the second purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_fiforet2}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_fiforet2")])
-
Process the reception of purchase order 2
-
+4 -30
View File
@@ -8,50 +8,24 @@
-
I confirm the purchase order.
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_5}
!python {model: purchase.order}: |
self.button_confirm(cr, uid, [ref("purchase_order_5")])
-
I check the "Approved" status after confirmed RFQ.
-
!assert {model: purchase.order, id: purchase_order_5}:
- state == 'approved'
- state == 'purchase'
-
First I cancel receptions related to this order if order shipped.
-
!python {model: purchase.order}: |
order = self.browse(cr, uid, ref("purchase_order_5"))
self.pool.get('stock.picking').action_cancel(cr, uid, [picking.id for picking in order.picking_ids])
-
I check order status in "Shipping Exception".
-
!python {model: purchase.order}: |
order = self.browse(cr, uid, ref("purchase_order_5"))
assert order.state == "except_picking", "order should be in Ship Exception state after cancel shipment"
-
Now I am able to cancel purchase order.
-
!python {model: purchase.order}: |
self.action_cancel(cr, uid, [ref("purchase_order_5")])
-
I check that order is cancelled.
-
!assert {model: purchase.order, id: purchase_order_5}:
- state == 'cancel'
-
After cancel the order, I check that it's related invoice cancelled.
-
!python {model: purchase.order}: |
order = self.browse(cr, uid, ref("purchase_order_5"))
assert order.invoice_ids[0].state == "cancel", "order's related invoice should be cancelled"
-
Now again set cancelled order to draft.
-
!python {model: purchase.order}: |
self.action_cancel_draft(cr, uid, [ref("purchase_order_5")])
-
Now I again to cancel draft order.
-
!python {model: purchase.order}: |
self.action_cancel(cr, uid, [ref("purchase_order_5")])
self.button_cancel(cr, uid, [ref("purchase_order_5")])
-
I check that order is cancelled.
-
@@ -1,29 +0,0 @@
-
Purchase user can create an invoice for order on receptions therfore test with that user which have Purchase user rights.
-
!context
uid: 'res_users_purchase_user'
-
I confirm another order where invoice control is 'Bases on incoming shipments'.
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_2}
-
I check that the invoice of order.
-
!python {model: purchase.order}: |
purchase_order = self.browse(cr, uid, ref("purchase_order_2"))
assert len(purchase_order.invoice_ids) == 0, "Invoice should not be generated on order confirmation."
-
Now I create an invoice for order on reception.
-
!python {model: purchase.order}: |
pick_ids = [self.browse(cr, uid, ref("purchase_order_2")).id]
self.action_invoice_create(cr, uid, pick_ids)
-
I check that the invoice of order.
-
!python {model: purchase.order}: |
purchase_order = self.browse(cr, uid, ref("purchase_order_2"))
assert len(purchase_order.invoice_ids) == 1, "Invoice should be generated."
@@ -1,25 +0,0 @@
-
Purchase User confirm the order and create invoice based on purchase order line.
-
!context
uid: 'res_users_purchase_user'
-
I confirm purchase order which has invoicing control method "Based on Purchase Order Lines".
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_6}
-
In order to test create invoice for purchase order line.
-
!python {model: purchase.order}: |
invoice_line_obj = self.pool.get('purchase.order.line_invoice')
purchase_order = self.browse(cr, uid, ref("purchase_order_6"))
context.update({'active_model': 'purchase.order', 'active_ids': [ref("purchase_order_6")]})
for purchase_line in purchase_order.order_line:
invoice_line_obj.makeInvoices(cr, uid, purchase_line.id, context=context)
-
I check the invoice of order.
-
!python {model: purchase.order}: |
purchase_order = self.browse(cr, uid, ref("purchase_order_6"))
for purchase_line in purchase_order.order_line:
assert len(purchase_order.invoice_ids) == 1, "Invoice should be generated."
@@ -1,44 +0,0 @@
-
Give access rights of Purchase user to merge two RFQ.
-
!context
uid: 'res_users_purchase_user'
-
In order to merge RFQ, I merge two RFQ which has same supplier and check new merged order.
-
!python {model: purchase.order}: |
context.update({"mail_create_nolog" : True })
order3 = self.browse(cr, uid, ref('purchase_order_4'))
order7 = self.browse(cr, uid, ref('purchase_order_7'))
total_qty = sum([x.product_qty for x in order3.order_line] + [x.product_qty for x in order7.order_line])
new_id = self.do_merge(cr, uid, [ref('purchase_order_4'), ref('purchase_order_7')], context=context)
assert order3.state == 'cancel', "Merged order should be canceled"
assert order7.state == 'cancel', "Merged order should be canceled"
def merged_data(lines):
product_id =[]
product_uom = []
res = {}
for line in lines:
product_id.append(line.product_id.id)
product_uom.append(line.product_uom.id)
res.update({'product_ids': product_id,'product_uom':product_uom})
return res
for order in self.browse(cr, uid, new_id.keys()):
assert order.state == 'draft',"New created order state should be in draft"
assert order.partner_id == order3.partner_id ,"partner is not correspond"
assert order.location_id == order3.location_id ,"Location is not correspond"
total_new_qty = sum(x.product_qty for x in order.order_line)
assert total_new_qty == total_qty,"product quantities are not correspond"
date_order = min(order3.date_order, order7.date_order)
assert order.date_order == date_order, "Date of order is not correspond"
n_product_data = merged_data(order.order_line)
o_product_data= merged_data(order3.order_line)
o_pro_data = merged_data(order7.order_line)
assert n_product_data == o_product_data or o_pro_data,"product data are not correspond"
@@ -1,70 +0,0 @@
-
In order to test the purchase order flow I compute the total of the listed products
-
I check the total untaxed amount of the RFQ is correctly computed
-
!python {model: purchase.order}: |
from openerp.tools import float_compare
po = self.browse(cr, uid, ref('purchase_order_1'))
assert float_compare(sum([l.price_subtotal for l in po.order_line]), po.amount_untaxed, precision_digits=2) == 0, "The amount of RFQ is not correctly computed"
-
I confirm the RFQ.
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_1}
-
I check the "Approved" status after confirmed RFQ.
-
!assert {model: purchase.order, id: purchase_order_1}:
- state == 'approved'
-
I check that the invoice details which is generated after confirmed RFQ.
-
!python {model: purchase.order}: |
from openerp.tools import float_compare
purchase_order = self.browse(cr, uid, ref("purchase_order_1"))
assert len(purchase_order.invoice_ids) >= 1, "Invoice is not generated more or less than one"
for invoice in purchase_order.invoice_ids:
assert invoice.state == "draft", "Invoice state should be draft"
assert invoice.partner_id.id == purchase_order.partner_id.id, "Vendor is not correspond with purchase order"
assert invoice.reference == purchase_order.partner_ref or purchase_order.name,"Invoice reference is not correspond with purchase order"
assert invoice.type == 'in_invoice',"Invoice type is not correspond with purchase order"
assert invoice.origin == purchase_order.name,"Invoice origin is not correspond with purchase order"
assert invoice.company_id.id == purchase_order.company_id.id ,"Invoice company is not correspond with purchase order"
assert float_compare(invoice.amount_untaxed, purchase_order.amount_untaxed, precision_digits=2) == 0, "Invoice untaxed amount is not correspond with purchase order"
assert float_compare(invoice.amount_tax, purchase_order.amount_tax, precision_digits=2) == 0, "Invoice tax amount is not correspond with purchase order"
assert float_compare(invoice.amount_total, purchase_order.amount_total, precision_digits=2) == 0, "Invoice total amount is not correspond with purchase order"
assert len(invoice.invoice_line_ids) == len(purchase_order.order_line), "Lines of Invoice and Purchase Order are not correspond"
-
I check that Reception details after confirmed RFQ.
-
!python {model: purchase.order}: |
purchase_order = self.browse(cr, uid, ref("purchase_order_1"))
assert len(purchase_order.picking_ids) >= 1, "You should have only one reception order"
for picking in purchase_order.picking_ids:
assert picking.state == "assigned", "Reception state should be in assigned state"
assert picking.partner_id.id == purchase_order.partner_id.id, "Delivery address of reception id is different from order"
assert picking.company_id.id == purchase_order.company_id.id, "Company is not correspond with purchase order"
-
Reception is ready for process so now done the reception.
-
!python {model: stock.picking}: |
pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_1"), context=context).picking_ids[0]
pick_ids.do_transfer()
-
I check that purchase order is shipped.
-
!python {model: purchase.order}: |
assert self.browse(cr, uid, ref("purchase_order_1")).shipped == True,"Purchase order should be delivered"
-
I Validate Invoice of Purchase Order.
-
!python {model: purchase.order}: |
for invoice in self.browse(cr, uid, ref('purchase_order_1'), context=context).invoice_ids:
invoice.signal_workflow('invoice_open')
-
I check that purchase order is invoiced.
-
!python {model: purchase.order}: |
assert self.browse(cr, uid, ref("purchase_order_1")).invoiced == True,"Purchase Order should be invoiced"
-3
View File
@@ -1,5 +1,2 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_purchase_to_invoice
from . import test_onchange_product_id
@@ -1,44 +0,0 @@
from openerp.tests.common import TransactionCase
class TestOnchangeProductId(TransactionCase):
"""Test that when an included tax is mapped by a fiscal position, the included tax must be
subtracted to the price of the product.
"""
def setUp(self):
super(TestOnchangeProductId, self).setUp()
self.fiscal_position_model = self.registry('account.fiscal.position')
self.fiscal_position_tax_model = self.registry('account.fiscal.position.tax')
self.tax_model = self.registry('account.tax')
self.res_partner_model = self.registry('res.partner')
self.product_model = self.registry('product.product')
self.product_uom_model = self.registry('product.uom')
self.po_line_model = self.registry('purchase.order.line')
def test_onchange_product_id(self):
cr, uid = self.cr, self.uid
uom_id = self.product_uom_model.search(cr, uid, [('name', '=', 'Unit(s)')])[0]
partner_id = self.res_partner_model.create(cr, uid, dict(name="George"))
tax_include_id = self.tax_model.create(cr, uid, dict(name="Include tax",
amount_type='percent',
amount='21.0',
type_tax_use='purchase',
price_include=True))
tax_exclude_id = self.tax_model.create(cr, uid, dict(name="Exclude tax",
amount_type='percent',
type_tax_use='purchase',
amount='0.00'))
product_id = self.product_model.create(cr, uid, dict(name="Voiture",
list_price='121',
supplier_taxes_id=[(6, 0, [tax_include_id])]))
fp_id = self.fiscal_position_model.create(cr, uid, dict(name="fiscal position",
sequence=1))
self.fiscal_position_tax_model.create(cr, uid, dict(position_id=fp_id,
tax_src_id=tax_include_id,
tax_dest_id=tax_exclude_id))
res = self.po_line_model.onchange_product_id(cr, uid, [], product_id, 1.0, uom_id, partner_id,
fiscal_position_id=fp_id)
self.assertEquals(0, res['value']['price_unit'], "The default price for products having no seller set is 0")
#TODO: add back a test on this
#self.assertEquals(100, res['value']['price_unit'], "The included tax must be subtracted to the price")
@@ -1,60 +0,0 @@
# -*- coding: utf-8 -*-
from openerp.tests import common
class TestPurchase(common.TransactionCase):
def test_purchase_to_invoice(self):
""" Testing for invoice create,validate and pay with invoicing and payment user."""
group_id = self.ref('account.group_account_invoice')
product_id = self.ref('product.product_category_3')
company_id = self.ref('base.main_company')
location_id = self.ref('stock.stock_location_3')
# Useful accounts
user_type_id = self.ref('account.data_account_type_expenses')
account_exp_id = self.env['account.account'].create({'code': 'X2020', 'name': 'Purchase - Test Expense Account', 'user_type_id': user_type_id, 'reconcile': True})
user_type_id = self.ref('account.data_account_type_payable')
account_pay_id = self.env['account.account'].create({'code': 'X1012', 'name': 'Purchase - Test Payable Account', 'user_type_id': user_type_id, 'reconcile': True})
self.env['product.product'].browse(product_id).product_tmpl_id.write({'property_account_expense_id': account_exp_id})
# Create Purchase Journal
self.env['account.journal'].create({'name': 'Purchase Journal - Test', 'code': 'PTPJ', 'type': 'purchase'})
# In order to test, I create new user and applied Invoicing & Payments group.
user = self.env['res.users'].with_context({'no_reset_password': True}).create({
'name': 'Test User',
'login': 'test@test.com',
'company_id': company_id,
'groups_id': [(6, 0, [group_id])]})
assert user, "User will not created."
# I create partner for purchase order.
partner = self.env['res.partner'].create({
'name': 'Test Customer',
'email': 'testcustomer@test.com',
'property_account_payable_id': account_pay_id,
})
# In order to test I create purchase order and confirmed it.
order = self.env['purchase.order'].create({
'partner_id': partner.id,
'location_id': location_id, })
self.env['purchase.order.line'].create({
'order_id': order.id,
'product_id': product_id,
'product_qty': 100.0,
'product_uom': 1,
'price_unit': 89.0,
'name': 'Service',
'date_planned': '2014-05-31'})
assert order, "purchase order will not created."
context = {"active_model": 'purchase.order', "active_ids": [order.id], "active_id": order.id}
order.with_context(context).wkf_confirm_order()
# In order to test I create invoice.
invoice = order.with_context(context).action_invoice_create()
assert invoice, "No any invoice is created for this purchase order"
# In order to test I validate invoice wihth Test User(invoicing and payment).
res = self.env['account.invoice'].browse(invoice).with_context(context).invoice_validate()
self.assertTrue(res, 'Invoice will not validated')
@@ -43,10 +43,6 @@
<strong>Order Date:</strong>
<p t-field="o.date_order"/>
</div>
<div t-if="o.validator" class="col-xs-3">
<strong>Validated By:</strong>
<p t-field="o.validator"/>
</div>
</div>
<table class="table table-condensed">
-5
View File
@@ -1,5 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import purchase_order_group
import purchase_line_invoice
@@ -1,99 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.osv import osv
from openerp.tools.translate import _
class purchase_line_invoice(osv.osv_memory):
""" To create invoice for purchase order line"""
_name = 'purchase.order.line_invoice'
_description = 'Purchase Order Line Make Invoice'
def _make_invoice_by_partner(self, cr, uid, partner, orders, lines_ids, context=None):
"""
create a new invoice for one vendor
@param cr : Cursor
@param uid : Id of current user
@param partner : The object partner
@param orders : The set of orders to add in the invoice
@param lines : The list of line's id
"""
purchase_obj = self.pool.get('purchase.order')
account_jrnl_obj = self.pool.get('account.journal')
invoice_obj = self.pool.get('account.invoice')
name = orders and orders[0].name or ''
journal_id = account_jrnl_obj\
.search(cr, uid, [('type', '=', 'purchase')], context=None)
journal_id = journal_id and journal_id[0] or False
a = partner.property_account_payable_id.id
inv = {
'name': name,
'origin': name,
'type': 'in_invoice',
'journal_id': journal_id,
'reference': partner.ref,
'account_id': a,
'partner_id': partner.id,
'invoice_line_ids': [(6, 0, lines_ids)],
'currency_id': orders[0].currency_id.id,
'comment': " \n".join([order.notes for order in orders if order.notes]),
'payment_term_id': orders[0].payment_term_id.id,
'fiscal_position_id': partner.property_account_position_id.id
}
inv_id = invoice_obj.create(cr, uid, inv, context=context)
purchase_obj.write(cr, uid, [order.id for order in orders], {'invoice_ids': [(4, inv_id)]}, context=context)
return inv_id
def makeInvoices(self, cr, uid, ids, context=None):
"""
To get Purchase Order line and create Invoice
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param context: A standard dictionary
@return : retrun view of Invoice
"""
if context is None:
context={}
record_ids = context.get('active_ids',[])
if record_ids:
res = False
invoices = {}
purchase_obj = self.pool.get('purchase.order')
purchase_line_obj = self.pool.get('purchase.order.line')
invoice_line_obj = self.pool.get('account.invoice.line')
for line in purchase_line_obj.browse(cr, uid, record_ids, context=context):
if (not line.invoiced) and (line.state not in ('draft', 'cancel')):
if not line.partner_id.id in invoices:
invoices[line.partner_id.id] = []
acc_id = purchase_obj._choose_account_from_po_line(cr, uid, line, context=context)
inv_line_data = purchase_obj._prepare_inv_line(cr, uid, acc_id, line, context=context)
inv_line_data.update({'origin': line.order_id.name})
inv_id = invoice_line_obj.create(cr, uid, inv_line_data, context=context)
purchase_line_obj.write(cr, uid, [line.id], {'invoiced': True, 'invoice_lines': [(4, inv_id)]})
invoices[line.partner_id.id].append((line,inv_id))
res = []
for result in invoices.values():
il = map(lambda x: x[1], result)
orders = list(set(map(lambda x : x[0].order_id, result)))
res.append(self._make_invoice_by_partner(cr, uid, orders[0].partner_id, orders, il, context=context))
return {
'domain': "[('id','in', ["+','.join(map(str,res))+"])]",
'name': _('Vendor Bills'),
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'account.invoice',
'view_id': False,
'context': "{'type':'in_invoice', 'journal_type': 'purchase'}",
'type': 'ir.actions.act_window'
}
@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Make the invoice-->
<record id="view_purchase_line_invoice" model="ir.ui.view">
<field name="name">Create invoices</field>
<field name="model">purchase.order.line_invoice</field>
<field name="arch" type="xml">
<form string="Select an Open Sales Order">
<group>
<label string="Do you want to generate the supplier bills?"/>
</group>
<footer>
<button name="makeInvoices" string="Confirm" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
<act_window name="Create invoices"
res_model="purchase.order.line_invoice"
src_model="purchase.order.line"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_view_purchase_line_invoice"/>
</data>
</openerp>
@@ -1,61 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import time
from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp.exceptions import UserError
class purchase_order_group(osv.osv_memory):
_name = "purchase.order.group"
_description = "Purchase Order Merge"
def fields_view_get(self, cr, uid, view_id=None, view_type='form',
context=None, toolbar=False, submenu=False):
"""
Changes the view dynamically
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param context: A standard dictionary
@return: New arch of view.
"""
if context is None:
context={}
res = super(purchase_order_group, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar,submenu=False)
if context.get('active_model','') == 'purchase.order' and len(context['active_ids']) < 2:
raise UserError(_('Please select multiple order to merge in the list view.'))
return res
def merge_orders(self, cr, uid, ids, context=None):
"""
To merge similar type of purchase orders.
@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: purchase order view
"""
order_obj = self.pool.get('purchase.order')
proc_obj = self.pool.get('procurement.order')
mod_obj =self.pool.get('ir.model.data')
if context is None:
context = {}
result = mod_obj._get_id(cr, uid, 'purchase', 'view_purchase_order_filter')
id = mod_obj.read(cr, uid, result, ['res_id'])
allorders = order_obj.do_merge(cr, uid, context.get('active_ids',[]), context)
return {
'domain': "[('id','in', [" + ','.join(map(str, allorders.keys())) + "])]",
'name': _('Purchase Orders'),
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'purchase.order',
'view_id': False,
'type': 'ir.actions.act_window',
'search_view_id': id['res_id']
}
@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_purchase_order_group" model="ir.ui.view">
<field name="name">Merger Purchase Orders</field>
<field name="model">purchase.order.group</field>
<field name="arch" type="xml">
<form string="Merge orders">
<group>
<separator string="Are you sure you want to merge these orders?"/>
<label string="
Please note that: &#10; &#10;
Orders will only be merged if: &#10;
* Purchase Orders are in draft &#10;
* Purchase Orders belong to the same supplier &#10;
* Purchase Orders are have same stock location, same pricelist, same currency &#10; &#10;
Lines will only be merged if: &#10;
* Order lines are exactly the same except for the product,quantity and unit &#10;
" colspan="4"/>
</group>
<footer>
<button name="merge_orders" string="Merge orders" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
<act_window name="Merge Purchase orders"
context="{'search_default_draft': 1, 'search_default_approved': False}"
res_model="purchase.order.group"
src_model="purchase.order"
view_mode="form"
target="new"
multi="True"
key2="client_action_multi"
id="action_view_purchase_order_group"/>
</data>
</openerp>