GoodERP
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

655 lines
29KB

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