Master so/po riddhi

This commit is contained in:
riddhikansaraflectra 2018-06-20 07:39:59 +00:00 committed by Parthiv Patel
parent a216e549e6
commit f27882fa3c
19 changed files with 950 additions and 1 deletions

View File

@ -0,0 +1,4 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import wizard
from . import models

View File

@ -0,0 +1,26 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
{
'name': 'Blanket Sale Order/Purchase Order',
'version': "1.0",
'category': 'Sales and Purchase Management',
'summary': 'A Blanket Sales/Purchase Order clearly lays out the terms '
'and conditions of a Sales/Purchase including quantities '
'required and when they are to be delivered.',
"author": "Flectra",
'website': 'https://flectrahq.com',
'depends': ['purchase', 'sale_stock'],
'data': [
'wizard/transfer_so_products_view.xml',
'wizard/transfer_po_products_view.xml',
'views/sale_view.xml',
'views/purchase_view.xml',
],
'demo': [
'demo/blanket_sale_demo.xml',
'demo/blanket_purchase_demo.xml'
],
'installable': True,
'application': False,
'auto_install': False,
}

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<flectra noupdate="1">
<record id="blanket_purchase_order" model="purchase.order">
<field name="partner_id" ref="base.res_partner_4"/>
</record>
<record id="blanket_purchase_order_line_1" model="purchase.order.line">
<field name="order_id" ref="blanket_purchase_order"/>
<field name="name">[RAM-SR5] RAM DDR SR5</field>
<field name="date_planned" eval="time.strftime('%Y/%m/10')"/>
<field name="product_id" ref="product.product_product_6"/>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">6000</field>
<field name="product_qty">10</field>
<field name="blanket_po_line" eval="True"/>
</record>
<record id="blanket_purchase_order_line_2" model="purchase.order.line">
<field name="order_id" ref="blanket_purchase_order"/>
<field name="name">[M-Wir] Mouse, Wireless]</field>
<field name="date_planned" eval="time.strftime('%Y/%m/10')"/>
<field name="product_id" ref="product.product_product_7"/>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">200</field>
<field name="product_qty">5</field>
<field name="blanket_po_line" eval="False"/>
</record>
<record id="blanket_purchase_order_line_3" model="purchase.order.line">
<field name="order_id" ref="blanket_purchase_order"/>
<field name="name">[MBi9] Motherboard I9P57</field>
<field name="date_planned" eval="time.strftime('%Y/%m/10')"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">3000</field>
<field name="product_qty">8</field>
<field name="blanket_po_line" eval="False"/>
</record>
</flectra>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<flectra noupdate="1">
<record id="sale_order_blanket1" model="sale.order">
<field name="partner_id" ref="base.res_partner_4"/>
<field name="partner_invoice_id" ref="base.res_partner_address_13"/>
<field name="partner_shipping_id" ref="base.res_partner_address_13"/>
<field name="user_id" ref="base.user_demo"/>
<field name="pricelist_id" ref="product.list0"/>
<field name="team_id" ref="sales_team.team_sales_department"/>
<field name="date_order"
eval="(DateTime.today() - relativedelta(months=1)).strftime('%Y-%m-%d %H:%M')"/>
</record>
<record id="sale_order_line_blanket_1" model="sale.order.line">
<field name="order_id" ref="sale_order_blanket1"/>
<field name="name">Laptop E5023</field>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">10</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">2950.00</field>
<field name="blanket_so_line" eval="True"/>
</record>
<record id="sale_order_line_blanket_2" model="sale.order.line">
<field name="order_id" ref="sale_order_blanket1"/>
<field name="name">Headset USB</field>
<field name="product_id" ref="product.product_delivery_01"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">2950.00</field>
<field name="blanket_so_line" eval="False"/>
</record>
<record id="sale_order_line_blanket_3" model="sale.order.line">
<field name="order_id" ref="sale_order_blanket1"/>
<field name="name">Webcamv</field>
<field name="product_id" ref="product.product_delivery_02"/>
<field name="product_uom_qty">10</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">45.00</field>
<field name="blanket_so_line" eval="False"/>
</record>
</flectra>

View File

@ -0,0 +1,5 @@
# Part of Flectra. See LICENSE file for full copyright and licensing
# details.
from . import sale
from . import purchase

View File

@ -0,0 +1,66 @@
# Part of Flectra. See LICENSE file for full copyright and licensing
# details.
from flectra import api, fields, models, _
from flectra.exceptions import Warning
class PurchaseOrder(models.Model):
_inherit = "purchase.order"
@api.multi
def button_cancel(self):
res = super(PurchaseOrder, self).button_cancel()
if self.order_line.filtered(
lambda l: l.blanket_po_line):
raise Warning(
_('Sorry, You can not cancel blanket line based PO.'))
self.write({'state': 'cancel'})
return res
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
@api.multi
def _prepare_stock_moves(self, picking):
res = super(PurchaseOrderLine, self)._prepare_stock_moves(picking)
self.ensure_one()
context = dict(self._context)
if self.product_id.type not in ['product',
'consu'] or self.blanket_po_line \
and not context.get('blanket'):
return []
qty = 0.0
for move in self.move_ids.filtered(
lambda x: x.state != 'cancel' and not
x.location_dest_id.usage == "supplier"):
qty += move.product_uom._compute_quantity(
move.product_uom_qty, self.product_uom,
rounding_method='HALF-UP')
for re in res:
if self.blanket_po_line and context.get('transfer_qty'):
re['product_uom_qty'] = context.get('transfer_qty')
else:
re['product_uom_qty'] = self.product_qty - qty
return res
blanket_po_line = fields.Boolean(string="Blanket Order", copy=False)
remaining_to_po_transfer = fields.Float(string="Remaining to Transfer",
copy=False)
@api.multi
def create(self, vals):
if vals.get('product_qty') and vals.get('blanket_po_line'):
vals.update(
{'remaining_to_po_transfer': vals.get('product_qty')})
res = super(PurchaseOrderLine, self).create(vals)
return res
@api.multi
def write(self, values):
result = super(PurchaseOrderLine, self).write(values)
for line in self:
if 'product_qty' and 'blanket_po_line' in values:
line.remaining_to_po_transfer = line.product_qty
return result

View File

@ -0,0 +1,114 @@
# Part of Flectra. See LICENSE file for full copyright and licensing
# details.
from flectra import api, models, fields
from flectra.exceptions import UserError
from flectra.tools import float_compare
class SaleOrder(models.Model):
_inherit = "sale.order"
class SaleOrderLine(models.Model):
_inherit = "sale.order.line"
_rec_name = 'product_id'
blanket_so_line = fields.Boolean(string="Blanket Order", copy=False)
remaining_to_so_transfer = fields.Float(string="Remaining to Transfer",
copy=False)
@api.multi
def _action_launch_procurement_rule(self):
"""
Launch procurement group run method with required/custom fields
genrated by a
sale order line. procurement group will launch '_run_move',
'_run_buy' or '_run_manufacture'
depending on the sale order line product rule.
"""
precision = self.env['decimal.precision'].precision_get(
'Product Unit of Measure')
errors = []
context = dict(self._context)
for line in self:
if line.state != 'sale' or not line.product_id.type in (
'consu', 'product') or line.blanket_so_line and \
not context.get('blanket'):
continue
qty = 0.0
for move in line.move_ids.filtered(lambda r: r.state != 'cancel'):
qty += move.product_uom._compute_quantity(move.product_uom_qty,
line.product_uom,
rounding_method='HALF-UP')
if float_compare(qty, line.product_uom_qty,
precision_digits=precision) >= 0:
continue
group_id = line.order_id.procurement_group_id
if not group_id:
group_id = self.env['procurement.group'].create({
'name': line.order_id.name,
'move_type': line.order_id.picking_policy,
'sale_id': line.order_id.id,
'partner_id': line.order_id.partner_shipping_id.id,
})
line.order_id.procurement_group_id = group_id
else:
# In case the procurement group is already created and the
# order was
# cancelled, we need to update certain values of the group.
updated_vals = {}
if group_id.partner_id != line.order_id.partner_shipping_id:
updated_vals.update(
{'partner_id': line.order_id.partner_shipping_id.id})
if group_id.move_type != line.order_id.picking_policy:
updated_vals.update(
{'move_type': line.order_id.picking_policy})
if updated_vals:
group_id.write(updated_vals)
values = line._prepare_procurement_values(group_id=group_id)
if line.blanket_so_line and context.get('blanket'):
product_qty = context.get('transfer_qty')
else:
product_qty = line.product_uom_qty - qty
procurement_uom = line.product_uom
quant_uom = line.product_id.uom_id
get_param = self.env['ir.config_parameter'].sudo().get_param
if procurement_uom.id != quant_uom.id and get_param(
'stock.propagate_uom') != '1':
product_qty = line.product_uom._compute_quantity(product_qty,
quant_uom,
rounding_method='HALF-UP')
procurement_uom = quant_uom
try:
self.env['procurement.group'].run(line.product_id, product_qty,
procurement_uom,
line.order_id.partner_shipping_id.property_stock_customer,
line.name,
line.order_id.name, values)
except UserError as error:
errors.append(error.name)
if errors:
raise UserError('\n'.join(errors))
return True
@api.multi
def create(self, vals):
if vals.get('product_uom_qty') and vals.get('blanket_so_line'):
vals.update(
{'remaining_to_so_transfer': vals.get('product_uom_qty')})
res = super(SaleOrderLine, self).create(vals)
return res
@api.multi
def write(self, values):
result = super(SaleOrderLine, self).write(values)
for line in self:
if 'product_uom_qty' and 'blanket_so_line' in values:
line.remaining_to_so_transfer = line.product_uom_qty
return result

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -0,0 +1,4 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import test_purchase_to_invoice_and_delivery
from . import test_sale_to_invoice_and_delivery

View File

@ -0,0 +1,175 @@
# Part of Flectra. See LICENSE file for full copyright and licensing
# details.
import logging
from flectra.exceptions import Warning
from flectra.tests.common import TransactionCase
class TestPurchaseOrder(TransactionCase):
def setUp(self):
super(TestPurchaseOrder, self).setUp()
self.stock_move = self.env['stock.move']
self.inv_obj = self.env['account.invoice']
self.purchase_wizard = self.env['purchase.transfer.products']
self.po1 = self.env.ref('blanket_so_po.blanket_purchase_order')
self.po_line_with_blanket = self.env.ref(
'blanket_so_po.blanket_purchase_order_line_1')
self.po_line_without_blanket = self.env.ref(
'blanket_so_po.blanket_purchase_order_line_2')
self.po_line_without_blanket2 = self.env.ref(
'blanket_so_po.blanket_purchase_order_line_3')
def test_2_purchase_with_blanket(self):
self.assertTrue(self.po1, 'Purchase: no purchase order created')
self.po1.button_confirm()
self.assertEqual(self.po1.state, 'purchase',
'Purchase: PO state should be "Purchase"')
self.assertTrue(self.po1.picking_ids, "Picking should be created.")
logging.info('Test Cases for Blanket Purchase order')
logging.info('Purchase Order - %s' % (self.po1.name))
logging.info(
'============================================================='
'==================+=====')
logging.info(
' | Blanket Po Line | Product | Ordered Qty | Remaining '
'to transfer | Received Qty |')
for line in self.po1.order_line:
logging.info(
' %s | %s | %d | %d '
' | %d ' % (
line.blanket_po_line, line.product_id.name,
line.product_qty,
line.remaining_to_po_transfer, line.qty_received))
logging.info(
'========================================================='
'========================')
#
blanket_lines_po = self.po1.order_line.search(
[('order_id', '=', self.po1.id),
('blanket_po_line', '=', True)])
uom_qty = self.po_line_with_blanket.product_qty
transfer_qty = 2
remaining_qty = 0.0
len_blanket_lines = len(blanket_lines_po)
total_po_line = len(self.po1.order_line)
move_lines = len(self.po1.picking_ids.move_lines)
logging.info(
'*****************************************************')
logging.info('Delivery Order for Purchase Order- %s' % (
self.po1.picking_ids.name))
logging.info(
'============================================================'
'===================+=====')
logging.info(
' | Product | Initial Demand | Reserved | Done |')
for move in self.po1.picking_ids.move_lines:
logging.info('| %s | %d |%d | %d' % (
move.product_id.name, move.product_uom_qty,
move.reserved_availability, move.quantity_done))
logging.info(
'========================================================'
'=========================')
self.assertEqual(move_lines, total_po_line - len_blanket_lines,
'There is no equal number of move lines in move')
self.assertTrue(self.po_line_with_blanket.blanket_po_line,
'Purchase: There is a Blanket po line')
remaining_qty = uom_qty - transfer_qty
transfer_wizard = self.purchase_wizard.create(
{'ref_id': self.po_line_with_blanket.id,
'transfer_qty': transfer_qty})
transfer_wizard.split_qty_wt_newline_po()
self.assertEqual(remaining_qty, uom_qty - transfer_qty,
'Remaining to transfer qty is different')
total_po_line = len(self.po1.order_line)
transfer_qty += 5
remaining_qty = uom_qty - transfer_qty
transfer_wizard = self.purchase_wizard.create(
{'ref_id': self.po_line_with_blanket.id, 'transfer_qty': 5})
transfer_wizard.split_qty_wt_newline_po()
self.assertEqual(remaining_qty, uom_qty - transfer_qty,
'Remaining to transfer qty is different')
logging.info(
'*****************************************************')
logging.info(
'Purchase Order after Blanket Split lines- %s' % (
self.po1.name))
logging.info(
'============================================================'
'===================+=====')
logging.info(
' | Blanket Po Line | Product | Ordered Qty | Remaining '
'to transfer | Received Qty |')
for line in self.po1.order_line:
logging.info(
' %s | %s | %d | %d '
' | %d ' % (
line.blanket_po_line, line.product_id.name,
line.product_qty,
line.remaining_to_po_transfer, line.qty_received))
logging.info(
'========================================================='
'========================')
with self.assertRaises(Warning):
self.po1.button_cancel()
self.picking = self.po1.picking_ids[0]
self.assertEqual(self.picking.move_lines[-1].quantity_done, 0.0)
self.assertEqual(self.picking.move_lines[-2].quantity_done, 0.0)
self.picking.move_lines[-1].quantity_done = 2
self.po1._compute_picking()
self.po1._compute_is_shipped()
logging.info(
'*****************************************************')
logging.info('Delivery Order - %s' % (self.picking.name))
logging.info(
'========================================================='
'======================+=====')
logging.info(
' id | Product | Initial Demand | Reserved | Done |')
for move in self.picking.move_lines:
logging.info(
'%d | %s | %d |%d | %d' % (
move.id, move.product_id.name, move.product_uom_qty,
move.reserved_availability, move.quantity_done))
logging.info(
'========================================================='
'========================')
self.picking.force_assign()
res_dict = self.picking.button_validate()
backorder_wizard = self.env[(res_dict.get('res_model'))].browse(
res_dict.get('res_id'))
backorder_wizard.process()
self.picking.action_done()
logging.info(
'*****************************************************')
logging.info('Purchase Order after validate Delivery order- %s' % (
self.po1.name))
logging.info(
'============================================================'
'===================+=====')
logging.info(
' | Blanket Po Line | Product | Ordered Qty | Remaining '
'to transfer | Received Qty |')
for line in self.po1.order_line:
logging.info(
' %s | %s | %d | %d '
' | %d ' % (
line.blanket_po_line, line.product_id.name,
line.product_qty,
line.remaining_to_po_transfer, line.qty_received))
logging.info(
'========================================================='
'========================')

View File

@ -0,0 +1,180 @@
# Part of Flectra. See LICENSE file for full copyright and licensing
# details.
import logging
from flectra.tests.common import TransactionCase
class TestSaleOrder(TransactionCase):
def setUp(self):
super(TestSaleOrder, self).setUp()
self.so_model = self.env['sale.order']
self.so_line_model = self.env['sale.order.line']
self.stock_picking_model = self.env['stock.picking']
self.stock_move_model = self.env['stock.move']
self.stock_location_model = self.env['stock.location']
self.sale_wizard = self.env['sale.transfer.products']
self.invoice_wizard = self.env['sale.advance.payment.inv']
self.sale1 = self.env.ref('blanket_so_po.sale_order_blanket1')
self.so_line_with_blanket = self.env.ref(
'blanket_so_po.sale_order_line_blanket_1')
self.so_line_without_blanket = self.env.ref(
'blanket_so_po.sale_order_line_blanket_2')
self.so_line_without_blanket2 = self.env.ref(
'blanket_so_po.sale_order_line_blanket_3')
self.inv_obj = self.env['account.invoice']
def test_1_sale_with_blanket(self):
self.sale1.force_quotation_send()
self.sale1.action_confirm()
self.assertTrue(self.sale1.state, 'sale')
self.assertTrue(self.sale1.invoice_status, 'to invoice')
logging.info('Test Cases for Blanket Sale order')
logging.info('Sale Order - %s' % (self.sale1.name))
logging.info(
'============================================================'
'===================+=====')
logging.info(
' | Blanket So Line | Product | Ordered Qty | Remaining '
'to transfer | Delivered |')
for line in self.sale1.order_line:
logging.info(
' %s | %s | %d | %d '
' | %d ' % (
line.blanket_so_line, line.product_id.name,
line.product_uom_qty, line.remaining_to_so_transfer,
line.qty_delivered))
logging.info(
'========================================================'
'=========================')
uom_qty = self.so_line_with_blanket.product_uom_qty
transfer_qty = 2
remaining_qty = 0.0
logging.info(
'*****************************************************')
logging.info(
'========================================================='
'======================+=====')
logging.info(
' | Product | Initial Demand | Reserved | Done |')
for picking in self.sale1.picking_ids:
for line in picking.move_lines:
logging.info('| %s | %d |%d | %d' % (
line.product_id.name, line.product_uom_qty,
line.reserved_availability, line.quantity_done))
logging.info(
'======================================================='
'==========================')
remaining_qty = uom_qty - transfer_qty
transfer_wizard = self.sale_wizard.create(
{'ref_id': self.so_line_with_blanket.id,
'transfer_qty': transfer_qty})
transfer_wizard.split_qty_wt_newline()
self.assertEqual(remaining_qty, uom_qty - transfer_qty,
'Remaining to transfer qty is different')
transfer_qty += 5
remaining_qty = uom_qty - transfer_qty
transfer_wizard = self.sale_wizard.create(
{'ref_id': self.so_line_with_blanket.id, 'transfer_qty': 5})
transfer_wizard.split_qty_wt_newline()
self.assertEqual(remaining_qty, uom_qty - transfer_qty,
'Remaining to transfer qty is different')
logging.info(
'*****************************************************')
logging.info(
'Sale Order after Blanket Split lines- %s' % (self.sale1.name))
logging.info(
'========================================================='
'======================+=====')
logging.info(
' | Blanket So Line | Product | Ordered Qty | Remaining '
'to transfer | Delivered |')
for line in self.sale1.order_line:
logging.info(
' %s | %s | %d | %d '
' | %d ' % (
line.blanket_so_line, line.product_id.name,
line.product_uom_qty, line.remaining_to_so_transfer,
line.qty_delivered))
logging.info(
'======================================================='
'==========================')
self.assertEqual(self.sale1.picking_ids.move_lines[-1].quantity_done,
0.0)
self.assertEqual(self.sale1.picking_ids.move_lines[-2].quantity_done,
0.0)
self.sale1.picking_ids.move_lines[-1].quantity_done = 2
logging.info(
'*****************************************************')
logging.info('Delivery Order - %s' % (self.sale1.picking_ids.name))
logging.info(
'==========================================================='
'====================+=====')
logging.info(
' | Product | Initial Demand | Reserved | Done |')
for move in self.sale1.picking_ids.move_lines:
logging.info('| %s | %d |%d | %d' % (
move.product_id.name, move.product_uom_qty,
move.reserved_availability, move.quantity_done))
logging.info(
'======================================================='
'==========================')
self.sale1.picking_ids.action_confirm()
self.sale1.picking_ids.action_assign()
res_dict = self.sale1.picking_ids.button_validate()
backorder_wizard = self.env[(res_dict.get('res_model'))].browse(
res_dict.get('res_id'))
backorder_wizard.process()
logging.info(
'*****************************************************')
logging.info(
'Sale Order after validate Delivery order- %s' % (
self.sale1.name))
logging.info(
'=========================================================='
'=====================+=====')
logging.info(
' | Blanket So Line | Product | Ordered Qty | Remaining '
'to transfer | Delivered |invoice status')
for line in self.sale1.order_line:
logging.info(
' %s | %s | %d | %d '
' | %d |%s' % (
line.blanket_so_line, line.product_id.name,
line.product_uom_qty, line.remaining_to_so_transfer,
line.qty_delivered, line.invoice_status))
logging.info(
'======================================================='
'==========================')
self.assertEqual(len(self.sale1.picking_ids), 2,
'There is no 2 pickings are available')
context = {"active_model": 'sale.order',
"active_ids": [self.sale1.id],
"active_id": self.sale1.id}
for invoice in self.sale1.invoice_ids:
logging.info('Invoice of Delivered Quantity.')
for line in invoice.invoice_line_ids:
logging.info(
'==================================================')
logging.info(
'| Product | Quantity | Unit Price | Subtotal |')
logging.info(
'=================================================|')
logging.info(
'|%s |%d |%d |%d | ' % (
line.product_id.name, line.quantity,
line.price_unit,
line.price_subtotal))
invoice.with_context(context).invoice_validate()

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<flectra>
<record id="inherit_blanket_purchase_order_form_view" model="ir.ui.view">
<field name="name">inherit.purchase.form.view</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="priority">1</field>
<field name="arch" type="xml">
<xpath expr="/form/sheet/notebook/page/field[@name='order_line']/form/sheet/group"
position="before">
<header>
<button name="%(action_purchase_transfer_products)d"
type="action" string="Transfer"
class="oe_highlight"
attrs="{'invisible':['|', '|', ('blanket_po_line', '=', False), ('remaining_to_po_transfer','&lt;=',0),('state','!=','purchase')]}"/>
</header>
</xpath>
<xpath expr="/form/sheet/notebook/page/field[@name='order_line']/form/sheet/group/group/div/field[@name='product_uom']"
position="before">
<field name="state" invisible="1"/>
</xpath>
<xpath expr="//field[@name='order_line']/tree"
position="attributes">
<attribute name="editable"/>
</xpath>
<xpath expr="/form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='name']"
position="after">
<field name='blanket_po_line'/>
</xpath>
<xpath expr="/form/sheet/notebook/page/field[@name='order_line']/form/sheet/group/group/field[@name='taxes_id']"
position="before">
<field name='blanket_po_line'
attrs="{'readonly':[('state','=','sale')]}"/>
</xpath>
<xpath expr="/form/sheet/notebook/page/field[@name='order_line']/form/sheet/group/group/field[@name='product_id']"
position="after">
<field name="remaining_to_po_transfer"
attrs="{'invisible':[('state','!=','purchase')]}"
string="Remaining to Transfer"/>
</xpath>
<xpath expr="/form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='qty_received']"
position="after">
<field name="remaining_to_po_transfer"
string="Remaining to Transfer"/>
</xpath>
</field>
</record>
</flectra>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<flectra>
<record id="inherit_blanket_sale_order_form_view" model="ir.ui.view">
<field name="name">inherit.sale.order.form.view</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="priority">1</field>
<field name="arch" type="xml">
<xpath expr="/form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='name']"
position="after">
<field name='blanket_so_line'/>
</xpath>
<xpath expr="/form/sheet/notebook/page/field[@name='order_line']/form/group/group/field[@name='tax_id']"
position="before">
<field name="blanket_so_line"
attrs="{'readonly':[('state','=','sale')]}"/>
</xpath>
<xpath expr="//field[@name='order_line']/form/group"
position="before">
<header>
<button name="%(action_sale_transfer_products)d"
type="action" string="Transfer"
class="oe_highlight"
attrs="{'invisible':['|', '|', ('blanket_so_line', '=', False), ('remaining_to_so_transfer','&lt;=',0),('state','!=','sale')]}"/>
</header>
</xpath>
<xpath expr="//field[@name='order_line']/tree"
position="attributes">
<attribute name="editable"/>
</xpath>
<xpath expr="/form/sheet/notebook/page/field[@name='order_line']/form/group/group/label[@for='product_uom_qty']"
position="before">
<field name="remaining_to_so_transfer"
attrs="{'invisible':[('state','!=','sale')]}"
string="Remaining to Transfer"/>
</xpath>
<xpath expr="/form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_uom_qty']"
position="after">
<field name="remaining_to_so_transfer"
string="Remaining to Transfer"/>
</xpath>
</field>
</record>
</flectra>

View File

@ -0,0 +1,6 @@
# Part of Flectra. See LICENSE file for full copyright and licensing
# details.
from . import transfer_po_products
from . import transfer_so_products

View File

@ -0,0 +1,56 @@
# Part of Flectra. See LICENSE file for full copyright and licensing
# details.
from flectra import api, fields, models, _
from flectra.exceptions import ValidationError
class PurchaseTransferProducts(models.TransientModel):
_name = 'purchase.transfer.products'
_description = 'Transfer products from Purchase Lines'
transfer_qty = fields.Float("Transfer Qty")
ref_id = fields.Many2one('purchase.order.line',
string="Product Reference",
readonly=True)
@api.model
def default_get(self, fields):
context = dict(self._context)
result = super(PurchaseTransferProducts, self).default_get(
fields)
purchase_line = self.env['purchase.order.line'].browse(
context.get('active_id'))
result.update({
'ref_id': purchase_line.id or False,
'transfer_qty': purchase_line.remaining_to_po_transfer})
return result
@api.multi
def split_qty_wt_newline_po(self):
self.ensure_one()
if self.ref_id.remaining_to_po_transfer < self.transfer_qty:
raise ValidationError(_(
'Sorry, You can not transfer more than requested or '
'remains!'))
elif self.transfer_qty <= 0:
raise ValidationError(_(
'Sorry, You can not transfer zero or negative '
'quantity!'))
self.ref_id._create_or_update_picking()
pickings = self.ref_id.order_id.picking_ids.filtered(
lambda p: p.state not in ('done', 'cancel'))
self.ref_id.remaining_to_po_transfer -= self.transfer_qty
for picking in pickings:
for line in picking.move_lines.filtered(
lambda l: l.product_id.id == self.ref_id.product_id.id and
l.purchase_line_id.id == self.ref_id.id):
total_product_qty = \
self.ref_id.remaining_to_po_transfer + \
self.ref_id.qty_received
line.product_uom_qty = \
self.ref_id.product_qty - total_product_qty
return {
'type': 'ir.actions.client',
'tag': 'reload',
}

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<flectra>
<record id="purchase_transfer_products_form_view" model="ir.ui.view">
<field name="name">purchase.transfer.products.form.view</field>
<field name="model">purchase.transfer.products</field>
<field name="arch" type="xml">
<form>
<group>
<group>
<field name="ref_id"/>
<field name="transfer_qty" default_focus="1"/>
</group>
</group>
<footer>
<button name="split_qty_wt_newline_po" string="Transfer"
type="object" class="oe_highlight"
context="{'blanket':True, 'transfer_qty':transfer_qty}"/>
or
<button special="cancel" string="Cancel"
class="oe_highlight"/>
</footer>
</form>
</field>
</record>
<record id="action_purchase_transfer_products"
model="ir.actions.act_window">
<field name="name">Transfer Products</field>
<field name="res_model">purchase.transfer.products</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="purchase_transfer_products_form_view"/>
<field name="target">new</field>
</record>
</flectra>

View File

@ -0,0 +1,52 @@
# Part of Flectra. See LICENSE file for full copyright and licensing
# details.
from flectra import api, fields, models, _
from flectra.exceptions import ValidationError
class SaleTransferProducts(models.TransientModel):
_name = 'sale.transfer.products'
_description = 'Transfer products from Sale Lines'
transfer_qty = fields.Float("Transfer Qty")
ref_id = fields.Many2one('sale.order.line', string="Product Reference",
readonly=True)
@api.model
def default_get(self, fields):
context = dict(self._context)
result = super(SaleTransferProducts, self).default_get(fields)
sale_line = self.env['sale.order.line'].browse(
context.get('active_id'))
result.update({
'ref_id': sale_line.id or False,
'transfer_qty': sale_line.remaining_to_so_transfer})
return result
@api.multi
def split_qty_wt_newline(self):
if self.ref_id.remaining_to_so_transfer < self.transfer_qty:
raise ValidationError(_(
'Sorry, You can not transfer more than requested or '
'remains!'))
elif self.transfer_qty <= 0:
raise ValidationError(_(
'Sorry, You can not transfer zero or negative '
'quantity!'))
self.ref_id._action_launch_procurement_rule()
pickings = self.ref_id.order_id.picking_ids.filtered(
lambda p: p.state not in ('done', 'cancel'))
self.ref_id.remaining_to_so_transfer -= self.transfer_qty
for picking in pickings:
for line in picking.move_lines.filtered(
lambda l: l.product_id.id == self.ref_id.product_id.id and
l.sale_line_id.id == self.ref_id.id):
total_product_qty = self.ref_id.remaining_to_so_transfer \
+ self.ref_id.qty_delivered
line.product_uom_qty = self.ref_id.product_uom_qty - \
total_product_qty
return {
'type': 'ir.actions.client',
'tag': 'reload',
}

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<flectra>
<record id="sale_transfer_products_form_view" model="ir.ui.view">
<field name="name">sale.transfer.products.form.view</field>
<field name="model">sale.transfer.products</field>
<field name="arch" type="xml">
<form>
<group>
<group>
<field name="ref_id"/>
<field name="transfer_qty" default_focus="1"/>
</group>
</group>
<footer>
<button name="split_qty_wt_newline" string="Transfer"
type="object" class="oe_highlight"
context="{'blanket':True, 'transfer_qty':transfer_qty}"/>
or
<button special="cancel" string="Cancel"
class="oe_highlight"/>
</footer>
</form>
</field>
</record>
<record id="action_sale_transfer_products"
model="ir.actions.act_window">
<field name="name">Transfer Products</field>
<field name="res_model">sale.transfer.products</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="sale_transfer_products_form_view"/>
<field name="target">new</field>
</record>
</flectra>

View File

@ -195,7 +195,7 @@ class TestStockValuation(TransactionCase):
wizard.process()
# the unit price of the stock move has been updated to the latest value
self.assertEquals(move1.price_unit, price_unit_usd_new_rate)
self.assertEquals(round(move1.price_unit), round(price_unit_usd_new_rate))
self.assertAlmostEqual(self.product1.stock_value, price_unit_usd_new_rate * 10, delta=0.1)