背景:
单个设备在没有业务唯一标识的情况创建业务单据时因网络原因出现异常,服务器接口其实已经正常接收,间隔一定时间后重新保存会出现重复单据
待调整的内容:
涉及到创建的单据有:调拨出库,配货退货,补货申请,库存损溢
在创建单据前根据统一接口(/api/v6/shop/order/order_no/get)获取单号,拿到单号后作为请求参数传入对应创建/更新接口中,服务器端根据单号判断是否存在进入创建或更新逻辑。
涉及到的接口有:
创建,修改调拨单(/api/v6/shop/pick/update/post)
创建,更新损溢单(/api/v6/shop/scrap/update/post)
创建,更新补货单(/api/v6/shop/reload/update/post)
1.新建业务单据表-(业务单号、业务类型、修改人、最后修改时间等字段)doc_no.py
# -*- coding: utf-8 -*-
import datetime
import logging
from openerp.osv import fields, osv
_logger = logging.getLogger(__name__)
business_type_item = {'sale':1, 'sale_return':2, 'sale_exchange':3, 'shop_pick_out':4, 'stock_move':5, 'refund':6, 'inventory':7, 'scrap':8, 'reload':9}
business_type_list = [(1, u'销售订单'), (2, u'销售退货'), (3, u'销售换货'), (4, u'调拨出库'),(5, u'本店移库'), (6, u'配货退货'), (7, u'盘点'), (8, u'损溢'), (9, u'补货申请')]
class nt_doc_no(osv.osv):
_name = "nt.doc.no"
_description = u"业务单号"
_columns = {
"business_type": fields.selection(business_type_list, u"业务类型", select=True),
"doc_no": fields.char(u"业务单号", size=32, required=True, select=True),
'write_uid': fields.many2one('res.users', u'最后修改者', readonly=True, ),
'write_date': fields.datetime(u'最后修改时间', readonly=True),
}
_sql_constraints = [
('nt_doc_type_no_uniq', 'unique(business_type,doc_no)', u'业务单号唯一')
]
def _auto_init(self, cr, context=None):
#初始化,查找索引,若无就创建
super(nt_doc_no, self)._auto_init(cr, context)
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname in %s', (('inx_nt_doc_type_no',),))
index_names =[rs[0] for rs in cr.fetchall()]
if 'inx_nt_doc_type_no' not in index_names:
cr.execute("create index inx_nt_doc_type_no on nt_doc_no(business_type,doc_no)")
cr.execute('ANALYZE nt_doc_no')
def _set_doc_no(self, cr, uid, doc_no, business_type=1, context=None):
#创建业务单号(openerp自带创建时间和创建人等字段)
if context is None:context = {}
cr.execute("""
INSERT INTO nt_doc_no
(create_uid,create_date,write_date,write_uid, business_type,doc_no)
VALUES
(%s,now(),now(),%s, %s, '%s') returning id
""" %(uid, uid, business_type,doc_no))
doc_no_id = cr.fetchone()[0]
return doc_no_id
def _get_doc_no(self, cr, uid, doc_no, business_type, context=None):
#获取业务单据方法
if context is None:context={}
cr.execute("""
select id from nt_doc_no where business_type=%s and doc_no = %s limit 1
""",(business_type, doc_no))
result = cr.fetchone()
return result and result[0] or False
2.编写tree视图doc_n0_view.xml
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="nt_doc_no_tree_view">
<field name="name">nt.doc.no.tree.view</field>
<field name="model">nt.doc.no</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="业务单号" create="0" delete="0" edit="0">
<field name="business_type"/>
<field name="doc_no"/>
<field name="write_uid"/>
<field name="write_date"/>
</tree>
</field>
</record>
<record id="action_nt_doc_no_tree_list" model="ir.actions.act_window">
<field name="name">业务单号</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">nt.doc.no</field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="context">{}</field>
<field name="domain">[]</field>
</record>
</data>
</openerp>
3.在统一获取订单编号接口,判断获取的business_type是什么,来找到对应的业务单据接口,调整业务逻辑
def get_pos_order_no(self, cr, uid, session):
data = request.json
# 默认取销售单号
business_type = data.get('business_type','sale')
if business_type_item.get(business_type,False):
# 细分方便后续单号规则拓展
if business_type == 'sale':
doc_no = self.pool.get('ir.sequence').get(cr, uid, 'sale.order.seq')
elif business_type == 'sale_return':
doc_no = self.pool.get('ir.sequence').get(cr, uid, 'nt.rma.seq')
elif business_type == 'sale_exchange':
doc_no = self.pool.get('ir.sequence').get(cr, uid, 'nt.rma.seq')
elif business_type == 'shop_pick_out':
doc_no = self.pool.get('ir.sequence').get(cr, uid, 'nt.shop.pick.seq')
elif business_type == 'stock_move':
doc_no = self.pool.get('ir.sequence').get(cr, uid, 'nt.shop.pick.seq')
elif business_type == 'refund':
doc_no = self.pool.get('ir.sequence').get(cr, uid, 'nt.shop.pick.seq')
elif business_type == 'inventory':
doc_no = self.pool.get('ir.sequence').get(cr, uid, 'nt.stock.inventory.plan.seq')
elif business_type == 'scrap':
doc_no = self.pool.get('ir.sequence').get(cr, uid, 'nt.shop.scrap.seq')
elif business_type == 'reload':
doc_no = self.pool.get('ir.sequence').get(cr, uid, 'nt.shop.reload.seq')
self.pool.get('nt.doc.no')._set_doc_no(cr, uid, doc_no, business_type_item[business_type])
return doc_no
else:
#无效的请求业务类型
raise_error(error.ERROR_INVALID_BUSINESS_TYPE)
4.调拨单接口增加业务逻辑/api/v6/shop/pick/update/post,获取调拨单号,查doc_no表中是否存在,如果不存在,直接报错
def upload_pick(pool, cr, uid, session):
data = request.json
pick_id = data.get('pick_id', False)
pick_no = data.get('pick_no','')
shop_id = session['shop_id']
if shop_id:
key = pick_id and '%s_%s'%(str(shop_id),str(pick_id)) or str(shop_id)
flag = helper.concurrnt_control(key, 3, 'PICK_UPDATE')
if flag != 1:
raise_error(error.ERROR_ORDER_PROCESSING, (u'更新',))
pick_obj = pool.get('nt.shop.pick')
self_instance = pool.get('nt.pos.api')
action_type = data.get('type','')
#若有调拨单号而没有id的话
if pick_no and not pick_id:
#查询doc_no,如果没有,则报错(请确认单号是否有效)
if not pool.get('nt.doc.no')._get_doc_no(cr, uid, pick_no, business_type_item.get(action_type,1)):
raise_error(WARNING_INVALID_DOC_NO)