forked from osbzr/gooderp_addons
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuy_adjust.py
244 lines (228 loc) · 12 KB
/
buy_adjust.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# -*- coding: utf-8 -*-
from odoo import fields, models, api
import odoo.addons.decimal_precision as dp
from odoo.exceptions import UserError
from odoo.tools import float_compare
# 订单确认状态可选值
BUY_ORDER_STATES = [
('draft', u'草稿'),
('done', u'已确认'),
('cancel', u'已作废')]
# 字段只读状态
READONLY_STATES = {
'done': [('readonly', True)],
}
class BuyAdjust(models.Model):
_name = "buy.adjust"
_inherit = ['mail.thread']
_description = u"采购变更单"
_order = 'date desc, id desc'
name = fields.Char(u'单据编号', copy=False,
help=u'变更单编号,保存时可自动生成')
order_id = fields.Many2one('buy.order', u'原始单据', states=READONLY_STATES,
copy=False, ondelete='restrict',
help=u'要调整的原始购货订单,只能调整已确认且没有全部入库的购货订单')
date = fields.Date(u'单据日期', states=READONLY_STATES,
default=lambda self: fields.Date.context_today(self),
index=True, copy=False,
help=u'变更单创建日期,默认是当前日期')
line_ids = fields.One2many('buy.adjust.line', 'order_id', u'变更单行',
states=READONLY_STATES, copy=True,
help=u'变更单明细行,不允许为空')
approve_uid = fields.Many2one('res.users', u'确认人',
copy=False, ondelete='restrict',
help=u'确认变更单的人')
state = fields.Selection(BUY_ORDER_STATES, u'确认状态',
index=True, copy=False,
default='draft',
help=u'变更单确认状态')
note = fields.Text(u'备注',
help=u'单据备注')
user_id = fields.Many2one(
'res.users',
u'经办人',
ondelete='restrict',
states=READONLY_STATES,
default=lambda self: self.env.user,
help=u'单据经办人',
)
company_id = fields.Many2one(
'res.company',
string=u'公司',
change_default=True,
default=lambda self: self.env['res.company']._company_default_get())
def _get_vals(self, line):
'''返回创建 buy order line 时所需数据'''
return {
'order_id': self.order_id.id,
'goods_id': line.goods_id.id,
'attribute_id': line.attribute_id.id,
'quantity': line.quantity,
'uom_id': line.uom_id.id,
'price_taxed': line.price_taxed,
'discount_rate': line.discount_rate,
'discount_amount': line.discount_amount,
'tax_rate': line.tax_rate,
'note': line.note or '',
}
@api.one
def buy_adjust_done(self):
'''确认采购变更单:
当调整后数量 < 原单据中已入库数量,则报错;
当调整后数量 > 原单据中已入库数量,则更新原单据及入库单分单的数量;
当调整后数量 = 原单据中已入库数量,则更新原单据数量,删除入库单分单;
当新增商品时,则更新原单据及入库单分单明细行。
'''
if self.state == 'done':
raise UserError(u'请不要重复确认!\n采购变更单%s已确认' % self.name)
if not self.line_ids:
raise UserError(u'请输入商品明细行!')
for line in self.line_ids:
if line.price_taxed < 0:
raise UserError(u'商品含税单价不能小于0!\n单价:%s' % line.price_taxed)
buy_receipt = self.env['buy.receipt'].search(
[('order_id', '=', self.order_id.id),
('state', '=', 'draft')])
if not buy_receipt:
raise UserError(u'采购入库单已全部入库,不能调整')
for line in self.line_ids:
# 检查属性是否填充,防止无权限人员不填就可以保存
if line.using_attribute and not line.attribute_id:
raise UserError(u'请输入商品:%s 的属性' % line.goods_id.name)
origin_line = self.env['buy.order.line'].search(
[('goods_id', '=', line.goods_id.id),
('attribute_id', '=', line.attribute_id.id),
('order_id', '=', self.order_id.id)])
if len(origin_line) > 1:
raise UserError(u'要调整的商品%s在原始单据中不唯一' % line.goods_id.name)
if origin_line:
origin_line.quantity += line.quantity # 调整后数量
new_note = u'变更单:%s %s。\n' % (self.name, line.note)
origin_line.note = (origin_line.note and
origin_line.note + new_note or new_note)
if origin_line.quantity < origin_line.quantity_in:
raise UserError(u'%s调整后数量不能小于原订单已入库数量' %
line.goods_id.name)
elif origin_line.quantity > origin_line.quantity_in:
# 查找出原购货订单产生的草稿状态的入库单明细行,并更新它
move_line = self.env['wh.move.line'].search(
[('buy_line_id', '=', origin_line.id),
('state', '=', 'draft')])
if move_line:
move_line.goods_qty += line.quantity
move_line.note = (move_line.note and
move_line.note or move_line.note + origin_line.note)
else:
raise UserError(u'商品%s已全部入库,建议新建购货订单' %
line.goods_id.name)
# 调整后数量与已入库数量相等时,删除产生的入库单分单
else:
buy_receipt.unlink()
else:
new_line = self.env['buy.order.line'].create(
self._get_vals(line))
receipt_line = []
if line.goods_id.force_batch_one:
i = 0
while i < line.quantity:
i += 1
receipt_line.append(
self.order_id.get_receipt_line(new_line, single=True))
else:
receipt_line.append(
self.order_id.get_receipt_line(new_line, single=False))
buy_receipt.write(
{'line_in_ids': [(0, 0, li[0]) for li in receipt_line]})
self.state = 'done'
self.approve_uid = self._uid
class BuyAdjustLine(models.Model):
_name = 'buy.adjust.line'
_description = u'采购变更单明细'
@api.one
@api.depends('goods_id')
def _compute_using_attribute(self):
'''返回订单行中商品是否使用属性'''
self.using_attribute = self.goods_id.attribute_ids and True or False
@api.one
@api.depends('quantity', 'price_taxed', 'discount_amount', 'tax_rate')
def _compute_all_amount(self):
'''当订单行的数量、单价、折扣额、税率改变时,改变购货金额、税额、价税合计'''
if self.tax_rate > 100:
raise UserError(u'税率不能输入超过100的数\n税率:%s!' % self.tax_rate)
if self.tax_rate < 0:
raise UserError(u'税率不能输入负数\n税率:%s!' % self.tax_rate)
self.subtotal = self.price_taxed * self.quantity - self.discount_amount # 价税合计
self.tax_amount = self.subtotal / \
(100 + self.tax_rate) * self.tax_rate # 税额
self.amount = self.subtotal - self.tax_amount # 金额
@api.onchange('price', 'tax_rate')
def onchange_price(self):
'''当订单行的不含税单价改变时,改变含税单价'''
price = self.price_taxed / (1 + self.tax_rate * 0.01) # 不含税单价
decimal = self.env.ref('core.decimal_price')
if float_compare(price, self.price, precision_digits=decimal.digits) != 0:
self.price_taxed = self.price * (1 + self.tax_rate * 0.01)
order_id = fields.Many2one('buy.adjust', u'订单编号', index=True,
required=True, ondelete='cascade',
help=u'关联的变更单编号')
goods_id = fields.Many2one('goods', u'商品', ondelete='restrict',
help=u'商品')
using_attribute = fields.Boolean(u'使用属性', compute=_compute_using_attribute,
help=u'商品是否使用属性')
attribute_id = fields.Many2one('attribute', u'属性',
ondelete='restrict',
domain="[('goods_id', '=', goods_id)]",
help=u'商品的属性,当商品有属性时,该字段必输')
uom_id = fields.Many2one('uom', u'单位', ondelete='restrict',
help=u'商品计量单位')
quantity = fields.Float(u'调整数量',
default=1,
required=True,
digits=dp.get_precision('Quantity'),
help=u'相对于原单据对应明细行的调整数量,可正可负')
price = fields.Float(u'购货单价',
store=True,
digits=dp.get_precision('Price'),
help=u'不含税单价,由含税单价计算得出')
price_taxed = fields.Float(u'含税单价',
digits=dp.get_precision('Price'),
help=u'含税单价,取自商品成本')
discount_rate = fields.Float(u'折扣率%',
help=u'折扣率')
discount_amount = fields.Float(u'折扣额',
digits=dp.get_precision('Amount'),
help=u'输入折扣率后自动计算得出,也可手动输入折扣额')
amount = fields.Float(u'金额', compute=_compute_all_amount,
store=True, readonly=True,
digits=dp.get_precision('Amount'),
help=u'金额 = 价税合计 - 税额')
tax_rate = fields.Float(u'税率(%)', default=lambda self: self.env.user.company_id.import_tax_rate,
help=u'默认值取公司进项税率')
tax_amount = fields.Float(u'税额', compute=_compute_all_amount,
store=True, readonly=True,
digits=dp.get_precision('Amount'),
help=u'由税率计算得出')
subtotal = fields.Float(u'价税合计', compute=_compute_all_amount,
store=True, readonly=True,
digits=dp.get_precision('Amount'),
help=u'含税单价 乘以 数量')
note = fields.Char(u'备注',
help=u'本行备注')
company_id = fields.Many2one(
'res.company',
string=u'公司',
change_default=True,
default=lambda self: self.env['res.company']._company_default_get())
@api.onchange('goods_id')
def onchange_goods_id(self):
'''当订单行的商品变化时,带出商品上的单位、默认仓库、成本价'''
if self.goods_id:
self.uom_id = self.goods_id.uom_id
self.price_taxed = self.goods_id.cost
self.tax_rate = self.goods_id.get_tax_rate(self.goods_id, self.order_id.order_id.partner_id, 'buy')
@api.onchange('quantity', 'price_taxed', 'discount_rate')
def onchange_discount_rate(self):
'''当数量、单价或优惠率发生变化时,优惠金额发生变化'''
self.price = self.price_taxed / (1 + self.tax_rate * 0.01)
self.discount_amount = (self.quantity * self.price *
self.discount_rate * 0.01)