GoodERP
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

415 rindas
16KB

  1. # -*- coding: utf-8 -*-
  2. from odoo import _
  3. from .utils import inherits, inherits_after, create_name, create_origin
  4. from odoo import models, fields, api
  5. from odoo.exceptions import UserError
  6. import logging
  7. _logger = logging.getLogger(__name__)
  8. class WhOut(models.Model):
  9. _name = 'wh.out'
  10. _description = '其他出库单'
  11. _inherit = ['mail.thread', 'barcodes.barcode_events_mixin']
  12. _order = 'date DESC, id DESC'
  13. _inherits = {
  14. 'wh.move': 'move_id',
  15. }
  16. TYPE_SELECTION = [
  17. ('inventory', '盘亏'),
  18. ('others', '其他出库')]
  19. move_id = fields.Many2one('wh.move', '移库单', required=True, index=True, ondelete='cascade',
  20. help='其他出库单对应的移库单')
  21. type = fields.Selection(TYPE_SELECTION, '业务类别', default='others',
  22. help='类别: 盘亏,其他出库')
  23. amount_total = fields.Float(compute='_get_amount_total', string='合计成本金额',
  24. store=True, readonly=True, digits='Amount',
  25. help='该出库单的出库金额总和')
  26. voucher_id = fields.Many2one('voucher', '出库凭证',
  27. readonly=True,
  28. help='该出库单的后生成的出库凭证')
  29. @inherits_after()
  30. def approve_order(self):
  31. for order in self:
  32. if order.state == 'done':
  33. raise UserError(_('请不要重复出库'))
  34. if self.env.user.company_id.is_enable_negative_stock: # 其他出库单检查负库存
  35. result_vals = self.env['wh.move'].create_zero_wh_in(self, self._name)
  36. if result_vals:
  37. return result_vals
  38. voucher = order.create_voucher()
  39. order.write({
  40. 'voucher_id': voucher and voucher[0] and voucher[0].id,
  41. 'state': 'done',
  42. })
  43. return True
  44. @inherits()
  45. def cancel_approved_order(self):
  46. for order in self:
  47. if order.state == 'draft':
  48. raise UserError(_('请不要重复撤销 %s') % self._description)
  49. order.delete_voucher()
  50. order.state = 'draft'
  51. return True
  52. @inherits()
  53. def unlink(self):
  54. for order in self:
  55. return order.move_id.unlink()
  56. @api.depends('line_out_ids.cost')
  57. def _get_amount_total(self):
  58. for wo in self:
  59. wo.amount_total = sum(line.cost for line in wo.line_out_ids)
  60. def get_move_origin(self, vals):
  61. return self._name + '.' + vals.get('type')
  62. @api.model_create_multi
  63. @create_name
  64. @create_origin
  65. def create(self, vals_list):
  66. return super(WhOut, self).create(vals_list)
  67. @api.onchange('type')
  68. def onchange_type(self):
  69. self.warehouse_dest_id = self.env['warehouse'].get_warehouse_by_type(
  70. self.type)
  71. def goods_inventory(self, vals):
  72. """
  73. 审核时若仓库中商品不足,则产生补货向导生成其他入库单并审核。
  74. :param vals: 创建其他入库单需要的字段及取值信息构成的字典
  75. :return:
  76. """
  77. auto_in = self.env['wh.in'].create(vals)
  78. self.with_context({'wh_in_line_ids': [line.id for line in
  79. auto_in.line_in_ids]}).approve_order()
  80. def create_voucher(self):
  81. '''
  82. 其他出库单生成出库凭证
  83. 借:如果出库类型为盘亏,取科目 1901 待处理财产损益;如果为其他,取核算类别的会计科目
  84. 贷:库存商品(商品分类上会计科目)
  85. '''
  86. voucher = self.env['voucher'].create({'date': self.date
  87. })
  88. credit_sum = 0 # 贷方之和
  89. for line in self.line_out_ids:
  90. if line.cost: # 贷方行(多行)
  91. self.env['voucher.line'].create({
  92. 'name': '%s %s' % (self.name, self.note or ''),
  93. 'account_id': line.goods_id.category_id.account_id.id,
  94. 'credit': line.cost,
  95. 'voucher_id': voucher.id,
  96. 'goods_id': line.goods_id.id,
  97. 'goods_qty': line.goods_qty,
  98. })
  99. credit_sum += line.cost
  100. account = self.type == 'inventory' \
  101. and self.env.ref('finance.small_business_chart1901') \
  102. or self.finance_category_id.account_id
  103. if credit_sum: # 借方行(汇总一行)
  104. self.env['voucher.line'].create({
  105. 'name': '%s %s' % (self.name, self.note or ''),
  106. 'account_id': account.id,
  107. 'auxiliary_id': self.auxiliary_id.id,
  108. 'debit': credit_sum,
  109. 'voucher_id': voucher.id,
  110. })
  111. if len(voucher.line_ids) > 0:
  112. voucher.voucher_done()
  113. return voucher
  114. else:
  115. voucher.unlink()
  116. def delete_voucher(self):
  117. # 反审核其他出库单时删除对应的出库凭证
  118. voucher = self.voucher_id
  119. if voucher.state == 'done':
  120. voucher.voucher_draft()
  121. voucher.unlink()
  122. def on_barcode_scanned(self, barcode):
  123. self.move_id.scan_barcode(self._name, barcode, self._origin.id)
  124. def action_batch_split(self):
  125. """其他出库单 按批次先进先出原则 批量拆分各批次商品 行"""
  126. for line_out in self.line_out_ids:
  127. res = line_out.env['wh.move.line'].search([ # 按商品去找出这个商品的所有批次数
  128. ('goods_id', '=', line_out.goods_id.id),
  129. ('state', '=', 'done'),
  130. ('lot', '!=', False),
  131. ('qty_remaining', '>', 0),
  132. ('warehouse_dest_id', '=', self.warehouse_id.id),
  133. ], order='lot asc, qty_remaining asc')
  134. if len(res):
  135. """
  136. 第一步:先把当前大于1的商品数量记下来
  137. 第二步:把这个商品行删除掉
  138. 第三步:按批次去拆分第一步记下来的数量
  139. """
  140. # 第一步:先把当前大于1的商品数量记下来
  141. wh_obj = line_out.env['wh.move.line'].search([
  142. ('goods_id', '=', line_out.goods_id.id),
  143. ('move_id', '=', line_out.move_id.id),
  144. ])
  145. v = sum(lin.goods_qty for lin in wh_obj)
  146. # 第二步:把这个商品行删除掉
  147. sql = """delete from wh_move_line where goods_id = '{}' and move_id = '{}'
  148. """.format(line_out.goods_id.id, line_out.move_id.id)
  149. self._cr.execute(sql)
  150. # 第三步:按批次去拆分第一步记下来的数量
  151. for line in res:
  152. if v <= 0:
  153. continue
  154. if v >= line.qty_remaining:
  155. vals = {
  156. 'move_id': line_out.move_id.id,
  157. 'goods_id': line_out.goods_id.id,
  158. 'lot': line.lot,
  159. 'lot_id': line.id,
  160. 'goods_qty': line.qty_remaining,
  161. 'type': 'out',
  162. 'cost_unit': line.cost_unit,
  163. 'cost': line.cost,
  164. 'expiration_date': line.expiration_date,
  165. }
  166. line_out.env['wh.move.line'].create(vals)
  167. v -= line.qty_remaining
  168. else:
  169. vals = {
  170. 'move_id': line_out.move_id.id,
  171. 'goods_id': line_out.goods_id.id,
  172. 'lot': line.lot,
  173. 'lot_id': line.id,
  174. 'goods_qty': v,
  175. 'type': 'out',
  176. 'cost_unit': line.cost_unit,
  177. 'cost': line.cost,
  178. 'expiration_date': line.expiration_date,
  179. }
  180. line_out.env['wh.move.line'].create(vals)
  181. v -= line.qty_remaining
  182. class WhIn(models.Model):
  183. _name = 'wh.in'
  184. _description = '其他入库单'
  185. _inherit = ['mail.thread']
  186. _order = 'date DESC, id DESC'
  187. _inherits = {
  188. 'wh.move': 'move_id',
  189. }
  190. TYPE_SELECTION = [
  191. ('inventory', '盘盈'),
  192. ('others', '其他入库'),
  193. ]
  194. move_id = fields.Many2one('wh.move', '移库单', required=True, index=True, ondelete='cascade',
  195. help='其他入库单对应的移库单')
  196. type = fields.Selection(TYPE_SELECTION, '业务类别', default='others',
  197. help='类别: 盘盈,其他入库,初始')
  198. amount_total = fields.Float(compute='_get_amount_total', string='合计成本金额',
  199. store=True, readonly=True, digits='Amount',
  200. help='该入库单的入库金额总和')
  201. voucher_id = fields.Many2one('voucher', '入库凭证',
  202. readonly=True,
  203. help='该入库单确认后生成的入库凭证')
  204. is_init = fields.Boolean('初始化单')
  205. @inherits()
  206. def approve_order(self):
  207. for order in self:
  208. if order.state == 'done':
  209. raise UserError(_('请不要重复入库'))
  210. voucher = order.create_voucher()
  211. order.write({
  212. 'voucher_id': voucher and voucher[0] and voucher[0].id,
  213. 'state': 'done',
  214. })
  215. return True
  216. @inherits()
  217. def cancel_approved_order(self):
  218. for order in self:
  219. if order.state == 'draft':
  220. raise UserError(_('请不要重复撤销 %s') % self._description)
  221. order.delete_voucher()
  222. order.state = 'draft'
  223. return True
  224. @inherits()
  225. def unlink(self):
  226. for order in self:
  227. return order.move_id.unlink()
  228. @api.depends('line_in_ids.cost')
  229. def _get_amount_total(self):
  230. self.amount_total = sum(line.cost for line in self.line_in_ids)
  231. def get_move_origin(self, vals):
  232. return self._name + '.' + vals.get('type')
  233. @api.model_create_multi
  234. @create_name
  235. @create_origin
  236. def create(self, vals_list):
  237. return super(WhIn, self).create(vals_list)
  238. @api.onchange('type')
  239. def onchange_type(self):
  240. self.warehouse_id = self.env['warehouse'].get_warehouse_by_type(
  241. self.type).id
  242. def create_voucher(self):
  243. # 入库单生成入库凭证
  244. '''
  245. 借:商品分类对应的会计科目 一般是库存商品
  246. 贷:如果入库类型为盘盈,取科目 1901 待处理财产损益(暂时写死)
  247. 如果入库类型为其他,取收发类别的会计科目
  248. '''
  249. # 初始化单的话,先找是否有初始化凭证,没有则新建一个
  250. if self.is_init:
  251. vouch_id = self.env['voucher'].search([('is_init', '=', True)])
  252. if not vouch_id:
  253. vouch_id = self.env['voucher'].create({'date': self.date,
  254. 'is_init': True
  255. })
  256. else:
  257. vouch_id = self.env['voucher'].create({'date': self.date
  258. })
  259. debit_sum = 0
  260. for line in self.line_in_ids:
  261. init_obj = self.is_init and 'init_warehouse - %s' % (self.id) or ''
  262. if line.cost:
  263. self.env['voucher.line'].create({
  264. 'name': '%s %s' % (self.name, self.note or ''),
  265. 'account_id': line.goods_id.category_id.account_id.id,
  266. 'debit': line.cost,
  267. 'voucher_id': vouch_id.id,
  268. 'goods_id': line.goods_id.id,
  269. 'goods_qty': line.goods_qty,
  270. 'init_obj': init_obj,
  271. })
  272. debit_sum += line.cost
  273. # 贷方科目: 如果是盘盈则取主营业务成本,否则取收发类别上的科目
  274. account = self.type == 'inventory' \
  275. and self.env.ref('finance.small_business_chart1901') \
  276. or self.finance_category_id.account_id
  277. if not self.is_init:
  278. if debit_sum:
  279. self.env['voucher.line'].create({
  280. 'name': '%s %s' % (self.name, self.note or ''),
  281. 'account_id': account.id,
  282. 'auxiliary_id': self.auxiliary_id.id,
  283. 'credit': debit_sum,
  284. 'voucher_id': vouch_id.id,
  285. })
  286. if not self.is_init:
  287. if len(vouch_id.line_ids) > 0:
  288. vouch_id.voucher_done()
  289. return vouch_id
  290. else:
  291. vouch_id.unlink()
  292. else:
  293. return vouch_id
  294. def delete_voucher(self):
  295. # 反审核入库单时删除对应的入库凭证
  296. if self.voucher_id:
  297. if self.voucher_id.state == 'done':
  298. self.voucher_id.voucher_draft()
  299. voucher = self.voucher_id
  300. # 始初化单反审核只删除明细行
  301. if self.is_init:
  302. vouch_obj = self.env['voucher'].search(
  303. [('id', '=', voucher.id)])
  304. vouch_obj_lines = self.env['voucher.line'].search([
  305. ('voucher_id', '=', vouch_obj.id),
  306. ('goods_id', 'in', [
  307. line.goods_id.id for line in self.line_in_ids]),
  308. ('init_obj', '=', 'init_warehouse - %s' % (self.id)), ])
  309. for vouch_obj_line in vouch_obj_lines:
  310. vouch_obj_line.unlink()
  311. else:
  312. voucher.unlink()
  313. class WhInternal(models.Model):
  314. _name = 'wh.internal'
  315. _description = '内部调拨单'
  316. _inherit = ['mail.thread']
  317. _order = 'date DESC, id DESC'
  318. _inherits = {
  319. 'wh.move': 'move_id',
  320. }
  321. move_id = fields.Many2one('wh.move', '移库单', required=True, index=True, ondelete='cascade',
  322. help='调拨单对应的移库单')
  323. amount_total = fields.Float(compute='_get_amount_total', string='合计成本金额',
  324. store=True, readonly=True, digits='Amount',
  325. help='该调拨单的出库金额总和')
  326. def goods_inventory(self, vals):
  327. """
  328. 审核时若仓库中商品不足,则产生补货向导生成其他入库单并审核。
  329. :param vals: 创建其他入库单需要的字段及取值信息构成的字典
  330. :return:
  331. """
  332. auto_in = self.env['wh.in'].create(vals)
  333. self.with_context({'wh_in_line_ids': [line.id for line in
  334. auto_in.line_in_ids]}).approve_order()
  335. @inherits_after()
  336. def approve_order(self):
  337. for order in self:
  338. if order.state == 'done':
  339. raise UserError(_('请不要重复入库'))
  340. if self.env.user.company_id.is_enable_negative_stock: # 移库单检查负库存
  341. result_vals = self.env['wh.move'].create_zero_wh_in(
  342. self, self._name)
  343. if result_vals:
  344. return result_vals
  345. order.state = 'done'
  346. return True
  347. @inherits()
  348. def cancel_approved_order(self):
  349. for order in self:
  350. if order.state == 'draft':
  351. raise UserError(_('请不要重复撤销 %s') % self._description)
  352. order.state = 'draft'
  353. return True
  354. @inherits()
  355. def unlink(self):
  356. for order in self:
  357. return order.move_id.unlink()
  358. @api.depends('line_out_ids.cost')
  359. def _get_amount_total(self):
  360. self.amount_total = sum(line.cost for line in self.line_out_ids)
  361. @api.model_create_multi
  362. @create_name
  363. @create_origin
  364. def create(self, vals_list):
  365. return super(WhInternal, self).create(vals_list)
上海开阖软件有限公司 沪ICP备12045867号-1