GoodERP
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

413 satır
16KB

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