add app_purchase

This commit is contained in:
ivan deng
2018-02-14 18:04:31 +08:00
parent 6fce3d4331
commit 79961b39ad
32 changed files with 992 additions and 1 deletions

View File

@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import product_set_supplier_wiz
from . import procurement_batch_generator

View File

@@ -0,0 +1,129 @@
# -*- encoding: utf-8 -*-
from odoo import models, fields, api, _
import odoo.addons.decimal_precision as dp
from odoo.exceptions import Warning
from datetime import datetime, timedelta
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
class ProcurementBatchGenerator(models.TransientModel):
_name = 'procurement.batch.generator'
_description = 'Wizard to create procurements from product tree'
route_ids = fields.Many2many('stock.location.route', string='Preferred Routes')
line_ids = fields.One2many(
'procurement.batch.generator.line', 'parent_id',
string='Procurement Request Lines')
@api.model
def default_get(self, fields):
res = super(ProcurementBatchGenerator, self).default_get(fields)
assert isinstance(self.env.context['active_ids'], list),\
"context['active_ids'] must be a list"
line_ids = []
warehouses = self.env['stock.warehouse'].search(
[('company_id', '=', self.env.user.company_id.id)])
warehouse_id = warehouses and warehouses[0].id or False
# product.template是被继承的所以用同样方法即可
for product in self.env['product.product'].browse(
self.env.context['active_ids']):
# todo: 库存的数量在此使用会导致运算量较大,停用。 如需要再加。未来可以考虑数据全部从前端送过来,不需再查数据库
# partner_id = product.seller_ids and product.seller_ids[0].id or False
if product.virtual_available < 0:
procurement_qty = product.virtual_available * -1
else:
procurement_qty = 1
line_ids.append([0, 0, {
'name': product.name,
'product_id': product.id,
# 'partner_id': partner_id,
# 'qty_available': product.qty_available,
'virtual_available': product.virtual_available,
# 'outgoing_qty': product.outgoing_qty,
# 'incoming_qty': product.incoming_qty,
'uom_id': product.uom_id.id,
# 按预测库存数补货or 1
'procurement_qty': procurement_qty,
'warehouse_id': warehouse_id,
'date_planned': datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT),
}])
try:
res.update({
'line_ids': line_ids,
})
except:
pass
return res
@api.multi
def validate(self):
self.ensure_one()
wiz = self[0]
assert wiz.line_ids, 'wizard must have some lines'
procs = self.env['procurement.order']
for line in wiz.line_ids:
if not line.procurement_qty:
continue
procurement = self.env['procurement.order'].create(
line._prepare_procurement_order())
procs += procurement
if not procs.ids:
raise Warning(_('All requested quantities are null.'))
# todo: 看是否需要记录工作流
# self.pool['procurement.order'].signal_workflow(
# self._cr, self._uid, new_po_ids, 'button_confirm')
# todo: 看是用 self.pool还是直接run当前用直接run
# self.pool['procurement.order'].run(
# self._cr, self._uid, new_po_ids, context=self.env.context)
procs.run()
action = self.env.ref('procurement.procurement_action').read()[0]
action['domain'] = [('id', 'in', procs.ids)]
return action
class ProcurementBatchGeneratorLine(models.TransientModel):
_name = 'procurement.batch.generator.line'
_description = 'Lines of the wizard to request procurements'
parent_id = fields.Many2one(
'procurement.batch.generator', string='Parent')
product_id = fields.Many2one(
'product.product', string='Product', readonly=True)
partner_id = fields.Many2one(
'res.partner', string='Supplier', required=False)
qty_available = fields.Float(
string='Quantity On Hand',
digits=dp.get_precision('Product Unit of Measure'), readonly=True)
virtual_available = fields.Float(
string='Forecast Quantity',
digits=dp.get_precision('Product Unit of Measure'), readonly=True)
outgoing_qty = fields.Float(
string='Incoming Quantity',
digits=dp.get_precision('Product Unit of Measure'), readonly=True)
incoming_qty = fields.Float(
string='Outgoing Quantity',
digits=dp.get_precision('Product Unit of Measure'), readonly=True)
procurement_qty = fields.Float(
string='Requested Quantity',
digits=dp.get_precision('Product Unit of Measure'), default=1)
uom_id = fields.Many2one(
'product.uom', string='Unit of Measure', readonly=True)
warehouse_id = fields.Many2one(
'stock.warehouse', string='Warehouse')
date_planned = fields.Datetime(string='Planned Date')
@api.multi
def _prepare_procurement_order(self):
self.ensure_one()
vals = {
'name': 'INT: %s' % (self.env.user.login),
'date_planned': self.date_planned,
'product_id': self.product_id.id,
'product_qty': self.procurement_qty,
'product_uom': self.uom_id.id,
'location_id': self.warehouse_id.lot_stock_id.id,
'company_id': self.warehouse_id.company_id.id,
'route_ids': [(6, 0, self.parent_id.route_ids.ids)],
}
return vals

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="procurement_batch_generator_wiz_form" model="ir.ui.view">
<field name="name">procurement.batch.generator.form</field>
<field name="model">procurement.batch.generator</field>
<field name="arch" type="xml">
<form string="Request Procurements">
<group>
<field name="route_ids" widget="many2many_tags" groups="stock.group_adv_location" invisible="1"/>
</group>
<group name="main">
<field name="line_ids" context="{'default_parent_id': active_id}" nolabel="1" colspan="2">
<tree editable="bottom" create="0" delete="0">
<field name="parent_id" invisible="1"/>
<field name="product_id"/>
<!--<field name="qty_available"/>-->
<field name="virtual_available"/>
<field name="uom_id" groups="product.group_uom"/>
<!--<field name="partner_id" readonly="1"/>-->
<field name="procurement_qty"/>
<field name="warehouse_id" options="{'no_open':True,'no_create':True}"/>
<field name="date_planned" widget="date"/>
</tree>
</field>
</group>
<footer>
<button type="object" name="validate"
string="Validate" class="oe_highlight"/>
<button special="cancel" string="Cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
<act_window id="procurement_batch_generator_tree_action"
multi="True"
key2="client_action_multi"
name="Request Procurements"
res_model="procurement.batch.generator"
src_model="product.template"
view_mode="form"
target="new"/>
<act_window id="procurement_batch_generator_tree_action2"
multi="True"
key2="client_action_multi"
name="Request Procurements"
res_model="procurement.batch.generator"
src_model="product.product"
view_mode="form"
target="new"/>
</data>
</openerp>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="product_set_supplier_wiz_form" model="ir.ui.view">
<field name="name">product.set.supplier.wiz.form</field>
<field name="model">product.set.supplier.wiz</field>
<field name="arch" type="xml">
<form string="Set Supplier">
<group>
<group><field name="name" options="{'no_create': True, 'no_open':True}"/></group>
<group><field name="create_uid" readonly="1"/></group>
</group>
<group>
<group>
<field name="min_qty"/>
<field name="price"/>
</group>
<group>
<label for="date_start" string="Validity From"/>
<newline/>
<field name="date_start" nolabel="1" class="oe_inline"/><field name="date_end" nolabel="1" class="oe_inline"/>
<!--<field name="delay"/>-->
</group>
</group>
<!--<separator string="要设置供应商的补货单(仅对采购类型,且异常的补货单生效)"/>-->
<separator string="Procurement list to setup supplier for the product"/>
<group>
<field name="p_ids" nolabel="1" widget="many2many_tags"/>
</group>
<footer>
<button name="set_supplier" type="object" string="Set supplier and run Scheduler" class="btn-primary"/>
<!--<button name="set_supplier" type="object" string="设定供应商并执行自动采购策略" class="btn-primary"/>-->
<button string="Cancel" class="btn-default" special="cancel"/>
<field name="view_po" nolabel="1" class="oe_inline" style="margin-left:50px"/>
<label for="view_po"/>
</footer>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="product_set_supplier_action">
<field name="name">Set Supplier</field>
<field name="res_model">product.set.supplier.wiz</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="product_set_supplier_wiz_form"/>
<field name="target">new</field>
</record>
<act_window id="action_product_set_supplier"
multi="True"
key2="client_action_multi" name="Set Supplier"
res_model="product.set.supplier.wiz" src_model="procurement.order"
view_mode="form" target="new" view_type="form"
/>
</data>
</odoo>

View File

@@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, _
from datetime import datetime, timedelta
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
import odoo.addons.decimal_precision as dp
from odoo.exceptions import UserError
import time
class ProductSetSupplierWiz(models.TransientModel):
_name = 'product.set.supplier.wiz'
_description = 'Set supplier for product'
name = fields.Many2one(
'res.partner', 'Vendor',
domain=[('supplier', '=', True)], ondelete='cascade', required=True,
help="Vendor of this product")
min_qty = fields.Float(
'Minimal Quantity', default=0.0, required=True,
help="The minimal quantity to purchase from this vendor, expressed in the vendor Product Unit of Measure if not any, in the default unit of measure of the product otherwise.")
price = fields.Float(
'Price', default=0.0, digits=dp.get_precision('Product Price'),
required=True, help="The price to purchase a product")
company_id = fields.Many2one(
'res.company', 'Company',
default=lambda self: self.env.user.company_id.id, index=1)
currency_id = fields.Many2one(
'res.currency', 'Currency',
default=lambda self: self.env.user.company_id.currency_id.id,
required=True)
date_start = fields.Date('Start Date', help="Start date for this vendor price")
date_end = fields.Date('End Date', help="End date for this vendor price")
delay = fields.Integer(
'Delivery Lead Time', default=1, required=True,
help="Lead time in days between the confirmation of the purchase order and the receipt of the products in your warehouse. Used by the scheduler for automatic computation of the purchase order planning.")
# 通过过滤得到要设置的补货单
p_ids = fields.Many2many('procurement.order', string='Procurement to set', readonly=True)
# 设置完后是否直接显示po
view_po = fields.Boolean('Show relate RFQ after set supplier', default=True)
# 默认值
@api.model
def default_get(self, fields):
res = super(ProductSetSupplierWiz, self).default_get(fields)
res['create_uid'] = self.env.user.id
if not res.get('min_qty'):
res['min_qty'] = 1
if not res.get('date_start'):
res['date_start'] = datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT)
if not res.get('date_end'):
res['date_end'] = (datetime.now() + timedelta(days=1)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
procs_ids = self.env.context.get('active_ids')
procs = self.env['procurement.order'].browse(procs_ids).filtered(lambda x: x.rule_id.action == 'buy' and x.state == 'exception')
p_ids = procs.ids
res['p_ids'] = p_ids
if len(p_ids) < 1:
raise UserError(_("Please select valid procurement orders. Only the 'status=Exception' and 'Buy in Inventory Routes' product can be set!"))
# 请选择有效的补货单。只有需要采购的异常补货单才可进行设置!
return res
# 为选定的产品设定供应商,只处理系统没处理的
@api.multi
def set_supplier(self):
self.ensure_one()
procs_ids = self.env.context.get('active_ids')
procs = self.env['procurement.order'].browse(procs_ids).filtered(lambda x: x.rule_id.action == 'buy' and x.state == 'exception')
t_ids = procs.mapped('product_id.product_tmpl_id').ids
# 去重复
t_ids = list(set(t_ids))
for t in t_ids:
self.env['product.supplierinfo'].create({
'name': self.name.id,
'product_tmpl_id': t,
'min_qty': self.min_qty,
'date_start': self.date_start,
'date_end': self.date_end,
'delay': self.delay,
})
time.sleep(1)
procs.run()
if self.view_po:
time.sleep(2)
p_names = procs.mapped('purchase_id.name')
p_names = list(set(p_names))
domain = [["name", "in", p_names]]
context = {
'search_default_name': p_names[0],
}
action = self.env.ref('purchase.purchase_rfq').read()[0]
if len(p_names) == 1:
action.update({
'context': context,
})
elif len(p_names) > 1:
action.update({
'domain': domain,
})
return action