GoodERP
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

647 Zeilen
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