GoodERP
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

647 lignes
30KB

  1. from odoo import fields, models, api
  2. from odoo.exceptions import UserError
  3. import datetime
  4. from odoo.tools import float_compare, float_is_zero
  5. # 字段只读状态
  6. READONLY_STATES = {
  7. 'done': [('readonly', True)],
  8. }
  9. ISODATEFORMAT = '%Y-%m-%d'
  10. class BuyReceipt(models.Model):
  11. _name = "buy.receipt"
  12. _inherits = {'wh.move': 'buy_move_id'}
  13. _inherit = ['mail.thread']
  14. _description = "采购入库单"
  15. _order = 'date desc, id desc'
  16. @api.depends('line_in_ids.subtotal', 'discount_amount',
  17. 'payment', 'line_out_ids.subtotal', 'delivery_fee', 'currency_id')
  18. def _compute_all_amount(self):
  19. """当优惠金额改变时,改变成交金额"""
  20. for s in self:
  21. total = 0
  22. if s.line_in_ids:
  23. # 收货时优惠前总金额
  24. total = sum(line.subtotal for line in s.line_in_ids)
  25. for line in s.line_in_ids:
  26. line.currency_id = s.currency_id
  27. elif s.line_out_ids:
  28. # 退货时优惠前总金额
  29. total = sum(line.subtotal for line in s.line_out_ids)
  30. for line in s.line_out_ids:
  31. line.currency_id = s.currency_id
  32. s.amount = total - s.discount_amount + s.delivery_fee
  33. # 获取当前汇率,用来计算当前的用本位币表示的成交金额。
  34. s.currency_rate = s.env['res.currency'].get_rate_silent(s.date, s.currency_id.id) or 1
  35. s.standard_amount = s.amount * s.currency_rate
  36. @api.depends('is_return', 'invoice_id.reconciled', 'invoice_id.amount')
  37. def _get_buy_money_state(self):
  38. """返回付款状态"""
  39. for s in self:
  40. if not s.is_return:
  41. if s.order_id.invoice_by_receipt:
  42. if s.invoice_id.reconciled == 0:
  43. s.money_state = '未付款'
  44. elif s.invoice_id.reconciled < s.invoice_id.amount:
  45. s.money_state = '部分付款'
  46. elif s.invoice_id.reconciled == s.invoice_id.amount:
  47. s.money_state = '全部付款'
  48. else:
  49. s.money_state = '不按收货结算'
  50. # 返回退款状态
  51. if s.is_return:
  52. if s.invoice_id.reconciled == 0:
  53. s.return_state = '未退款'
  54. elif abs(s.invoice_id.reconciled) < abs(s.invoice_id.amount):
  55. s.return_state = '部分退款'
  56. elif s.invoice_id.reconciled == s.invoice_id.amount:
  57. s.return_state = '全部退款'
  58. buy_move_id = fields.Many2one('wh.move', '入库单',
  59. required=True, ondelete='cascade',
  60. help='入库单号')
  61. is_return = fields.Boolean('是否退货',
  62. default=lambda self: self.env.context.get(
  63. 'is_return'),
  64. help='是否为退货类型')
  65. order_id = fields.Many2one('buy.order', '订单号',
  66. copy=False, ondelete='cascade',
  67. help='产生入库单/退货单的采购订单')
  68. invoice_id = fields.Many2one('money.invoice', '发票号', copy=False,
  69. ondelete='set null',
  70. help='产生的发票号')
  71. date_due = fields.Date('到期日期', copy=False,
  72. default=lambda self: fields.Date.context_today(
  73. self),
  74. help='付款截止日期')
  75. discount_rate = fields.Float('优惠率(%)',
  76. help='整单优惠率')
  77. discount_amount = fields.Float('优惠金额',
  78. digits='Amount',
  79. help='整单优惠金额,可由优惠率自动计算得出,也可手动输入')
  80. invoice_by_receipt = fields.Boolean(string="按收货结算", default=True,
  81. help='如未勾选此项,可在资金行里输入付款金额,订单保存后,采购人员可以单击资金行上的【确认】按钮。')
  82. amount = fields.Float('成交金额', compute=_compute_all_amount,
  83. store=True, readonly=True,
  84. digits='Amount',
  85. help='总金额减去优惠金额')
  86. standard_amount = fields.Float('本位币成交金额', compute=_compute_all_amount,
  87. store=True, readonly=True,
  88. digits='总数',
  89. help='本位币的成交金额')
  90. payment = fields.Float('本次付款',
  91. digits='Amount',
  92. help='本次付款金额')
  93. bank_account_id = fields.Many2one('bank.account', '结算账户',
  94. ondelete='restrict',
  95. help='用来核算和监督企业与其他单位或个人之间的债权债务的结算情况')
  96. cost_line_ids = fields.One2many('cost.line', 'buy_id', '采购费用', copy=False,
  97. help='采购费用明细行')
  98. money_state = fields.Char('付款状态', compute=_get_buy_money_state,
  99. store=True, default='未付款',
  100. help="采购入库单的付款状态",
  101. index=True, copy=False)
  102. return_state = fields.Char('退款状态', compute=_get_buy_money_state,
  103. store=True, default='未退款',
  104. help="采购退货单的退款状态",
  105. index=True, copy=False)
  106. voucher_id = fields.Many2one('voucher', '入库凭证', readonly=True,
  107. copy=False,
  108. help='入库时产生的入库凭证')
  109. origin_id = fields.Many2one('buy.receipt', '来源单据', copy=False)
  110. currency_id = fields.Many2one('res.currency',
  111. '外币币别',
  112. help='外币币别')
  113. is_multi_currency = fields.Boolean('多币种', related='company_id.is_multi_currency')
  114. currency_rate = fields.Float('汇率', digits='Price')
  115. delivery_fee = fields.Float('运费')
  116. money_order_id = fields.Many2one(
  117. 'money.order',
  118. '付款单',
  119. readonly=True,
  120. copy=False,
  121. help='输入本次付款确认时产生的付款单')
  122. project_id = fields.Many2one('project', '项目')
  123. def set_today(self):
  124. self.date = fields.Date.today()
  125. def _compute_total(self, line_ids):
  126. return sum(line.subtotal for line in line_ids)
  127. @api.onchange('discount_rate', 'line_in_ids', 'line_out_ids')
  128. def onchange_discount_rate(self):
  129. """当优惠率或订单行发生变化时,单据优惠金额发生变化"""
  130. line = self.line_in_ids or self.line_out_ids
  131. total = self._compute_total(line)
  132. if self.discount_rate:
  133. self.discount_amount = total * self.discount_rate * 0.01
  134. @api.onchange('partner_id')
  135. def onchange_partner_id(self):
  136. if self.partner_id:
  137. self.currency_id = self.partner_id.s_category_id.account_id.currency_id or self.env.company.currency_id
  138. for line in self.line_in_ids:
  139. line.tax_rate = line.goods_id.get_tax_rate(line.goods_id, self.partner_id, 'buy')
  140. def get_move_origin(self, vals):
  141. return self._name + (self.env.context.get('is_return') and
  142. '.return' or '.buy')
  143. @api.model_create_multi
  144. def create(self, vals_list):
  145. '''创建采购入库单时生成有序编号'''
  146. if not self.env.context.get('is_return'):
  147. name = self._name
  148. else:
  149. name = 'buy.return'
  150. for vals in vals_list:
  151. if vals.get('name', '/') == '/':
  152. vals['name'] = self.env['ir.sequence'].next_by_code(name) or '/'
  153. vals.update({
  154. 'origin': self.get_move_origin(vals),
  155. 'finance_category_id': self.env.ref('finance.categ_buy_goods').id,
  156. })
  157. return super(BuyReceipt, self).create(vals_list)
  158. def unlink(self):
  159. return self.buy_move_id.unlink()
  160. def _wrong_receipt_done(self):
  161. self.ensure_one()
  162. if self.state == 'done':
  163. raise UserError('请不要重复入库')
  164. batch_one_list_wh = []
  165. batch_one_list = []
  166. for line in self.line_in_ids:
  167. if line.amount < 0:
  168. raise UserError('采购金额不能小于 0!请修改。')
  169. if line.goods_id.force_batch_one:
  170. wh_move_lines = self.env['wh.move.line'].search(
  171. [('state', '=', 'done'), ('type', '=', 'in'), ('goods_id', '=', line.goods_id.id)])
  172. for move_line in wh_move_lines:
  173. if (move_line.goods_id.id, move_line.lot) not in batch_one_list_wh and move_line.lot:
  174. batch_one_list_wh.append(
  175. (move_line.goods_id.id, move_line.lot))
  176. if (line.goods_id.id, line.lot) in batch_one_list_wh:
  177. raise UserError('仓库已存在相同序列号的商品!\n商品:%s 序列号:%s' %
  178. (line.goods_id.name, line.lot))
  179. for line in self.line_in_ids:
  180. if line.goods_qty <= 0 or line.price_taxed < 0:
  181. raise UserError('商品 %s 的数量和含税单价不能小于0!' % line.goods_id.name)
  182. if line.goods_id.force_batch_one:
  183. batch_one_list.append((line.goods_id.id, line.lot))
  184. if len(batch_one_list) > len(set(batch_one_list)):
  185. raise UserError('不能创建相同序列号的商品!\n 序列号列表为%s' %
  186. [lot[1] for lot in batch_one_list])
  187. for line in self.line_out_ids:
  188. if line.amount < 0:
  189. raise UserError('退货金额不能小于 0!请修改。')
  190. if line.goods_qty <= 0 or line.price_taxed < 0:
  191. raise UserError('商品 %s 的数量和含税单价不能小于0!' % line.goods_id.name)
  192. if not self.bank_account_id and self.payment:
  193. raise UserError('付款额不为空时,请选择结算账户!')
  194. decimal_amount = self.env.ref('core.decimal_amount')
  195. if float_compare(self.payment, self.amount, precision_digits=decimal_amount.digits) == 1:
  196. raise UserError('本次付款金额不能大于折后金额!\n付款金额:%s 折后金额:%s' %
  197. (self.payment, self.amount))
  198. if float_compare(sum(cost_line.standard_amount for cost_line in self.cost_line_ids),
  199. sum(line.share_cost for line in self.line_in_ids),
  200. precision_digits=decimal_amount.digits) != 0:
  201. raise UserError('采购费用还未分摊或分摊不正确!\n采购费用:%s 分摊总费用:%s' %
  202. (sum(cost_line.standard_amount for cost_line in self.cost_line_ids),
  203. sum(line.share_cost for line in self.line_in_ids)))
  204. return
  205. def _line_qty_write(self):
  206. self.ensure_one()
  207. if self.order_id:
  208. for line in self.line_in_ids:
  209. decimal_quantity = self.env.ref('core.decimal_quantity')
  210. if float_compare(
  211. line.buy_line_id.quantity_in + line.goods_qty,
  212. line.buy_line_id.quantity,
  213. decimal_quantity.digits) == 1:
  214. if not line.goods_id.excess:
  215. raise UserError('%s收货数量大于订单数量' % line.goods_id.name)
  216. line.buy_line_id.quantity_in += line.goods_qty
  217. for line in self.line_out_ids: # 退货单行
  218. if self.order_id.type == 'return': # 退货类型的buy_order生成的采购退货单审核
  219. line.buy_line_id.quantity_in += line.goods_qty
  220. else:
  221. line.buy_line_id.quantity_in -= line.goods_qty
  222. return
  223. def _get_invoice_vals(self, partner_id, category_id, date, amount, tax_amount, currency_id):
  224. """返回创建 money_invoice 时所需数据"""
  225. return {
  226. 'move_id': self.buy_move_id.id,
  227. 'name': self.name,
  228. 'partner_id': partner_id.id,
  229. 'pay_method': self.order_id.pay_method.id or partner_id.pay_method.id,
  230. 'currency_id': currency_id.id if currency_id and currency_id != self.env.company.currency_id else False,
  231. 'category_id': category_id.id,
  232. 'date': date,
  233. 'amount': amount,
  234. 'reconciled': 0,
  235. 'to_reconcile': amount,
  236. 'tax_amount': tax_amount,
  237. 'date_due': self.date_due,
  238. 'state': 'draft',
  239. }
  240. def _receipt_make_invoice(self):
  241. '''入库单/退货单 生成结算单'''
  242. invoice_id = False
  243. if not self.is_return:
  244. if not self.invoice_by_receipt:
  245. return False
  246. amount = self.amount
  247. tax_amount = sum(line.tax_amount for line in self.line_in_ids)
  248. amount -= self.discount_amount
  249. else:
  250. amount = -self.amount
  251. tax_amount = - sum(line.tax_amount for line in self.line_out_ids)
  252. amount += self.discount_amount
  253. categ = self.env.ref('money.core_category_purchase')
  254. if not float_is_zero(amount, 2):
  255. invoice_id = self.env['money.invoice'].create(
  256. self._get_invoice_vals(
  257. self.partner_id, categ, self.date, amount, tax_amount, self.currency_id)
  258. )
  259. return invoice_id
  260. def _buy_amount_to_invoice(self):
  261. """采购费用产生结算单"""
  262. self.ensure_one()
  263. invoice_id = False
  264. if sum(cost_line.amount for cost_line in self.cost_line_ids) > 0:
  265. for line in self.cost_line_ids:
  266. if not float_is_zero(line.amount, 2):
  267. self.env['money.invoice'].create(
  268. self._get_invoice_vals(line.partner_id, line.category_id, self.date, line.amount + line.tax,
  269. line.tax, line.currency_id)
  270. )
  271. return invoice_id
  272. def _make_payment(self, invoice_id, amount, this_reconcile):
  273. """根据传入的invoice_id生成付款单"""
  274. categ = self.env.ref('money.core_category_purchase')
  275. money_lines = [
  276. {'bank_id': self.bank_account_id.id, 'amount': this_reconcile}]
  277. source_lines = [{'name': invoice_id.id,
  278. 'category_id': categ.id,
  279. 'date': invoice_id.date,
  280. 'amount': amount,
  281. 'reconciled': 0.0,
  282. 'to_reconcile': amount,
  283. 'this_reconcile': this_reconcile}]
  284. rec = self.with_context(type='pay')
  285. money_order = rec.env['money.order'].create({
  286. 'partner_id': self.partner_id.id,
  287. 'bank_name': self.partner_id.bank_name,
  288. 'bank_num': self.partner_id.bank_num,
  289. 'date': fields.Date.context_today(self),
  290. 'line_ids':
  291. [(0, 0, line) for line in money_lines],
  292. 'source_ids':
  293. [(0, 0, line) for line in source_lines] if invoice_id.state == 'done' else False,
  294. 'amount': amount,
  295. 'reconciled': this_reconcile,
  296. 'to_reconcile': amount,
  297. 'state': 'draft',
  298. 'origin_name': self.name,
  299. 'buy_id': self.order_id.id,
  300. })
  301. return money_order
  302. def _create_voucher_line(self, account_id, voucher_id, goods_id,
  303. goods_qty, partner_id, currency_id, currency_amount, share_cost):
  304. # 如果记账科目的币种未设置,就按本位币处理,如设置,就按外币处理
  305. if currency_id and currency_id != self.env.company.currency_id:
  306. voucher = self.env['voucher.line'].create({
  307. 'name': '%s %s' % (self.name, ''),
  308. 'account_id': account_id and account_id.id,
  309. 'partner_id': partner_id and partner_id.id,
  310. 'debit': 0 if currency_amount > 0 else -currency_amount * currency_id.rate - share_cost,
  311. 'credit': currency_amount * currency_id.rate if currency_amount > 0 else 0,
  312. 'voucher_id': voucher_id and voucher_id.id,
  313. 'goods_id': goods_id and goods_id.id,
  314. 'goods_qty': goods_qty,
  315. 'currency_id': currency_id.id,
  316. 'currency_amount': currency_amount if currency_amount > 0 else -currency_amount,
  317. 'rate_silent': currency_id.rate,
  318. })
  319. else:
  320. voucher = self.env['voucher.line'].create({
  321. 'name': '%s %s' % (self.name, ''),
  322. 'account_id': account_id and account_id.id,
  323. 'partner_id': partner_id and partner_id.id,
  324. 'debit': 0 if currency_amount > 0 else -currency_amount - share_cost,
  325. 'credit': currency_amount if currency_amount > 0 else 0,
  326. 'voucher_id': voucher_id and voucher_id.id,
  327. 'goods_id': goods_id and goods_id.id,
  328. 'goods_qty': goods_qty,
  329. })
  330. '''返回voucher line'''
  331. return voucher
  332. def create_voucher(self):
  333. """
  334. 借: 库存分类对应的会计科目 一般是库存料品
  335. 贷:类型为支出的类别对应的会计科目 一般是材料采购
  336. 当一张收货单有多个料品的时候,按对应科目汇总生成多个借方凭证行。
  337. 采购退货单生成的金额为负
  338. """
  339. self.ensure_one()
  340. vouch_id = self.env['voucher'].sudo().create({'date': self.date, 'ref': '%s,%s' % (self._name, self.id)})
  341. sum_amount = 0
  342. if not self.is_return:
  343. for line in self.line_in_ids:
  344. if line.standard_amount:
  345. # 借方明细
  346. self._create_voucher_line(line.goods_id.category_id.account_id,
  347. vouch_id, line.goods_id, line.goods_qty, False,
  348. line.goods_id.category_id.account_id.currency_id,
  349. -line.standard_amount, -line.share_cost)
  350. sum_amount += line.standard_amount
  351. if sum_amount:
  352. # 贷方明细
  353. self._create_voucher_line(self.buy_move_id.finance_category_id.account_id,
  354. vouch_id, False, 0, self.partner_id,
  355. self.buy_move_id.finance_category_id.account_id.currency_id, sum_amount, 0)
  356. for l in self.cost_line_ids:
  357. self._create_voucher_line(l.category_id.account_id,
  358. vouch_id, False, 0, l.partner_id,
  359. l.category_id.account_id.currency_id, l.amount, 0)
  360. if self.is_return:
  361. for line in self.line_out_ids:
  362. if line.amount:
  363. # 借方明细
  364. self._create_voucher_line(line.goods_id.category_id.account_id,
  365. vouch_id, line.goods_id, line.goods_qty, False,
  366. line.goods_id.category_id.account_id.currency_id,
  367. line.amount, 0)
  368. sum_amount += line.amount
  369. if sum_amount:
  370. # 贷方明细
  371. self._create_voucher_line(self.buy_move_id.finance_category_id.account_id,
  372. vouch_id, False, 0, self.partner_id, self.currency_id, -sum_amount, 0)
  373. if len(vouch_id.line_ids) > 0:
  374. vouch_id.voucher_done()
  375. return vouch_id
  376. else:
  377. vouch_id.unlink()
  378. def buy_receipt_done(self):
  379. """审核采购收货单/退货单,更新本单的付款状态/退款状态,并生成结算单和付款单"""
  380. self.ensure_one()
  381. # 报错
  382. self._wrong_receipt_done()
  383. # 调用wh.move中审核方法,更新审核人和审核状态
  384. self.buy_move_id.approve_order()
  385. # 将收货/退货数量写入订单行
  386. self._line_qty_write()
  387. # 创建入库的会计凭证
  388. voucher = self.create_voucher()
  389. # 收货单/退货单 生成结算单
  390. invoice_id = self._receipt_make_invoice()
  391. # 采购费用产生结算单
  392. self._buy_amount_to_invoice()
  393. # 生成付款单
  394. money_order = False
  395. if self.payment:
  396. flag = not self.is_return and 1 or -1
  397. amount = flag * self.amount
  398. this_reconcile = flag * self.payment
  399. money_order = self._make_payment(invoice_id, amount, this_reconcile)
  400. self.write({
  401. 'voucher_id': voucher and voucher.id,
  402. 'invoice_id': invoice_id and invoice_id.id,
  403. 'money_order_id': money_order and money_order.id,
  404. 'state': 'done', # 为保证审批流程顺畅,否则,未审批就可审核
  405. })
  406. if self.order_id:
  407. # 如果已退货也已退款,不生成新的分单
  408. if self.is_return and self.payment:
  409. return True
  410. # 产生新的入库单时,如果已经存在草稿的入库单时,先将已经存在的草稿进行删除
  411. self.env['buy.receipt'].search(['&', ('state', '=', 'draft'), '&', ('order_id', '=', self.order_id.id),
  412. ('is_return', '=', False)]).unlink()
  413. return self.order_id.buy_generate_receipt()
  414. def buy_receipt_draft(self):
  415. """反审核采购收货单/退货单,更新本单的付款状态/退款状态,并删除生成的结算单、付款单及凭证"""
  416. self.ensure_one()
  417. if self.state == 'draft':
  418. raise UserError('请不要重复撤销 %s' % self._description)
  419. # 查找产生的结算单(除了供应商的发票还有可能是采购费用发票)
  420. invoice_ids = self.env['money.invoice'].search([('name', '=', self.name)])
  421. for invoice in invoice_ids:
  422. # 不能反审核已核销的发货单
  423. if invoice.reconciled != 0:
  424. raise UserError('发票已核销,不能撤销入库!')
  425. if invoice.state == 'done':
  426. if self.env.company.draft_invoice:
  427. raise UserError('发票已收不可撤销入库')
  428. invoice.money_invoice_draft()
  429. invoice.unlink()
  430. # 反审核采购入库单时删除对应的入库凭证
  431. voucher = self.voucher_id
  432. if voucher.state == 'done':
  433. voucher.voucher_draft()
  434. voucher.unlink()
  435. self.write({
  436. 'state': 'draft',
  437. })
  438. # 修改订单行中已执行数量
  439. if self.order_id:
  440. for line in self.line_in_ids:
  441. line.buy_line_id.quantity_in -= line.goods_qty
  442. for line in self.line_out_ids:
  443. if self.order_id.type == 'return':
  444. line.buy_line_id.quantity_in -= line.goods_qty
  445. else:
  446. line.buy_line_id.quantity_in += line.goods_qty
  447. # 调用wh.move中反审核方法,更新审核人和审核状态
  448. self.buy_move_id.cancel_approved_order()
  449. def buy_share_cost(self):
  450. '''入库单上的采购费用分摊到入库单明细行上'''
  451. self.ensure_one()
  452. total_amount = 0
  453. for line in self.line_in_ids:
  454. total_amount += line.amount
  455. if not total_amount:
  456. raise UserError('收货单明细的采购总金额为0,请手动分摊!')
  457. cost = sum(cost_line.standard_amount for cost_line in self.cost_line_ids)
  458. for line in self.line_in_ids:
  459. line.share_cost = cost / total_amount * line.amount
  460. share_cost = sum(line.share_cost for line in self.line_in_ids)
  461. diff_cost = cost - share_cost
  462. self.line_in_ids[0].share_cost = self.line_in_ids[0].share_cost + diff_cost
  463. self.line_in_ids._compute_cost()
  464. self.line_in_ids._inverse_cost()
  465. return True
  466. def buy_to_return(self):
  467. '''采购入库单转化为采购退货单'''
  468. return_goods = {}
  469. return_order_draft = self.search([
  470. ('is_return', '=', True),
  471. ('origin_id', '=', self.id),
  472. ('state', '=', 'draft')
  473. ])
  474. if return_order_draft:
  475. raise UserError('采购入库单存在草稿状态的退货单!')
  476. return_order = self.search([
  477. ('is_return', '=', True),
  478. ('origin_id', '=', self.id),
  479. ('state', '=', 'done')
  480. ])
  481. for order in return_order:
  482. for return_line in order.line_out_ids:
  483. # 用产品、属性、批次做key记录已退货数量
  484. t_key = (return_line.goods_id.id,
  485. return_line.attribute_id.id, return_line.lot_id.lot)
  486. if return_goods.get(t_key):
  487. return_goods[t_key] += return_line.goods_qty
  488. else:
  489. return_goods[t_key] = return_line.goods_qty
  490. receipt_line = []
  491. for line in self.line_in_ids:
  492. qty = line.goods_qty
  493. l_key = (line.goods_id.id, line.attribute_id.id, line.lot)
  494. if return_goods.get(l_key):
  495. qty = qty - return_goods[l_key]
  496. if qty > 0:
  497. dic = {
  498. 'goods_id': line.goods_id.id,
  499. 'attribute_id': line.attribute_id.id,
  500. 'uom_id': line.uom_id.id,
  501. 'warehouse_id': line.warehouse_dest_id.id,
  502. 'warehouse_dest_id': line.warehouse_id.id,
  503. 'buy_line_id': line.buy_line_id.id,
  504. 'goods_qty': qty,
  505. 'price_taxed': line.price_taxed,
  506. 'price': line.price,
  507. 'tax_rate': line.tax_rate,
  508. 'cost_unit': line.cost_unit,
  509. 'discount_rate': line.discount_rate,
  510. 'discount_amount': line.discount_amount,
  511. 'type': 'out'
  512. }
  513. receipt_line.append(dic)
  514. if len(receipt_line) == 0:
  515. raise UserError('该订单已全部退货!')
  516. vals = {'partner_id': self.partner_id.id,
  517. 'is_return': True,
  518. 'order_id': self.order_id.id,
  519. 'origin_id': self.id,
  520. 'origin': 'buy.receipt.return',
  521. 'warehouse_dest_id': self.warehouse_id.id,
  522. 'warehouse_id': self.warehouse_dest_id.id,
  523. 'bank_account_id': self.bank_account_id.id,
  524. 'date_due': (datetime.datetime.now()).strftime(ISODATEFORMAT),
  525. 'date': (datetime.datetime.now()).strftime(ISODATEFORMAT),
  526. 'line_out_ids': [(0, 0, line) for line in receipt_line],
  527. 'discount_amount': self.discount_amount,
  528. }
  529. delivery_return = self.with_context(is_return=True).create(vals)
  530. view_id = self.env.ref('buy.buy_return_form').id
  531. name = '采购退货单'
  532. return {
  533. 'name': name,
  534. 'view_mode': 'form',
  535. 'view_id': False,
  536. 'views': [(view_id, 'form')],
  537. 'res_model': 'buy.receipt',
  538. 'type': 'ir.actions.act_window',
  539. 'res_id': delivery_return.id,
  540. 'target': 'current'
  541. }
  542. class WhMoveLine(models.Model):
  543. _inherit = 'wh.move.line'
  544. buy_line_id = fields.Many2one('buy.order.line',
  545. '采购单行', ondelete='cascade',
  546. help='对应的采购订单行')
  547. def _buy_get_price_and_tax(self):
  548. self.tax_rate = self.env.user.company_id.import_tax_rate
  549. self.price_taxed = self.goods_id.cost
  550. order_id = self.buy_line_id and self.buy_line_id.order_id.id or self.env.context.get('order_id')
  551. if order_id:
  552. line_domain = [
  553. ('order_id', '=', order_id),
  554. ('goods_id', '=', self.goods_id.id)
  555. ]
  556. # 如果行有属性,添加进搜索条件
  557. if self.attribute_id:
  558. line_domain.append(('attribute_id', '=', self.attribute_id.id))
  559. else:
  560. pass
  561. line = self.env['buy.order.line'].search(line_domain, limit=1)
  562. if line:
  563. self.buy_line_id = line.id
  564. self.uos_id = line.goods_id.uos_id.id
  565. self.uom_id = line.uom_id.id
  566. self.cost_unit = line.price
  567. self.price = line.price
  568. self.price_taxed = line.price_taxed
  569. self.discount_rate = line.discount_rate
  570. self.tax_rate = line.tax_rate
  571. self.plan_date = line.order_id.planned_date
  572. else:
  573. raise UserError('无此商品的订单行')
  574. @api.onchange('attribute_id')
  575. def onchange_attribute_id(self):
  576. '''当订单行的商品属性变化时,计算准确的采购订单行'''
  577. self.ensure_one()
  578. if self.attribute_id:
  579. self._buy_get_price_and_tax()
  580. @api.onchange('goods_id')
  581. def onchange_goods_id(self):
  582. '''当订单行的商品变化时,带出商品上的成本价,以及公司的进项税'''
  583. self.ensure_one()
  584. if self.goods_id:
  585. is_return = self.env.context.get('default_is_return')
  586. # 如果是采购入库单行 或 采购退货单行
  587. if is_return is not None and \
  588. ((self.type == 'in' and not is_return) or (self.type == 'out' and is_return)):
  589. self._buy_get_price_and_tax()
  590. return super(WhMoveLine, self).onchange_goods_id()
上海开阖软件有限公司 沪ICP备12045867号-1