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.

516 lines
24KB

  1. # -*- coding: utf-8 -*-
  2. ##############################################################################
  3. #
  4. # OpenERP, Open Source Management Solution
  5. # Copyright (C) 2016 武康开源软件(宣一敏).
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as
  9. # published by the Free Software Foundation, either version 3 of the
  10. # License, or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. #
  20. ##############################################################################
  21. from odoo import api, fields, models, tools, _
  22. from lxml import etree
  23. from odoo.exceptions import UserError
  24. import base64
  25. import io
  26. import zipfile
  27. from datetime import date
  28. class SpecificBusinessTypes(models.Model):
  29. _name = 'specific.business.types'
  30. _description = '特定业务类型'
  31. _rec_name= 'code'
  32. code = fields.Char('编码')
  33. name = fields.Char('名称')
  34. active = fields.Boolean(default=True)
  35. class IdType(models.Model):
  36. _name = 'id.type'
  37. _description = '证件类型'
  38. _rec_name= 'code'
  39. code = fields.Char('编码')
  40. name = fields.Char('名称')
  41. active = fields.Boolean(default=True)
  42. class AbandonedCollection(models.Model):
  43. _name = 'abandoned.collection'
  44. _description = '放弃享受减按1%征收率原因'
  45. _rec_name= 'code'
  46. code = fields.Char('编码')
  47. name = fields.Char('名称')
  48. active = fields.Boolean(default=True)
  49. class AccountMove(models.Model):
  50. _inherit = 'account.move'
  51. """
  52. 客户生成销售xml,存附件
  53. 供应商生成xml,存附件
  54. 批量生成xml。
  55. """
  56. cn_invoice_type = fields.Many2one('cn.invoice.type', string='发票类型')
  57. cn_invoice_type_code = fields.Char(string='发票类型编码', related='cn_invoice_type.code', store=True)
  58. specific_business_types = fields.Many2one('specific.business.types', string='特定业务类型')
  59. is_taxed = fields.Boolean('是否含税', default=False, compute='_compute_is_taxed', store=True)
  60. is_natural_person = fields.Boolean('受票方自然人标识', default=False, compute='_compute_is_company', store=True)
  61. id_type = fields.Many2one('id.type', string='证件类型')
  62. is_show_buy_bank = fields.Boolean('是否展示购买方银行账号', default=True, compute='_compute_show_bank', store=True)
  63. is_show_sell_bank = fields.Boolean('是否展示销售方银行账号', default=True, compute='_compute_show_bank', store=True)
  64. abandoned_collection = fields.Many2one('abandoned.collection', string='放弃享受减按1%征收率原因')
  65. payee = fields.Char(string='收款人')
  66. checker = fields.Char(string='收款人')
  67. @api.depends('partner_id', 'partner_id.company_type')
  68. def _compute_is_company(self):
  69. self.ensure_one()
  70. if self.partner_id and self.partner_id.company_type == 'company':
  71. self.is_natural_person = False
  72. else:
  73. self.is_natural_person = True
  74. @api.depends('move_type', 'partner_id', 'partner_id.bank_ids', 'partner_bank_id')
  75. def _compute_show_bank(self):
  76. self.ensure_one()
  77. if self.move_type == 'out_invoice': # 销售发票
  78. if self.partner_id.bank_ids:
  79. self.is_show_buy_bank = True
  80. else:
  81. self.is_show_buy_bank = False
  82. if self.partner_bank_id:
  83. self.is_show_sell_bank = True
  84. else:
  85. self.is_show_sell_bank = False
  86. else:
  87. if self.partner_id.bank_ids:
  88. self.is_show_sell_bank = True
  89. else:
  90. self.is_show_sell_bank = False
  91. if self.env.company.bank_ids:
  92. self.is_show_buy_bank = True
  93. else:
  94. self.is_show_buy_bank = False
  95. @api.depends("invoice_line_ids", "invoice_line_ids.tax_ids", "invoice_line_ids.tax_ids.price_include")
  96. def _compute_is_taxed(self):
  97. self.ensure_one()
  98. line_taxed = []
  99. for line in self.invoice_line_ids:
  100. line_taxed = line_taxed + [tax.price_include for tax in line.tax_ids]
  101. taxed = list(set(line_taxed))
  102. if len(taxed) > 1:
  103. raise UserError('明细行不可以即含税又不含税')
  104. if taxed:
  105. if taxed[0] == True:
  106. self.is_taxed = True
  107. else:
  108. self.is_taxed = False
  109. def action_to_cn_invoice(self):
  110. return {
  111. 'name': _('导出发票'),
  112. 'res_model': 'account.to.cn.invoice',
  113. 'view_mode': 'form',
  114. 'context': {
  115. 'active_model': 'account.move',
  116. 'active_ids': self.ids,
  117. },
  118. 'target': 'new',
  119. 'type': 'ir.actions.act_window',
  120. }
  121. def to_cn_invoice_dz_xml(self):
  122. # 清掉已开票,用于生成xml
  123. for line in self.invoice_line_ids:
  124. line.write({
  125. 'is_cn_invoice': False,
  126. })
  127. # 开始写xml
  128. business = etree.Element("business", comment=u"发票开具", id="FPKJ")
  129. self._to_dz_xml_top(business)
  130. tree = etree.ElementTree(business)
  131. xml_content = etree.tostring(tree, pretty_print=True, encoding="GBK")
  132. attachment = self.env['ir.attachment'].create({
  133. 'type': 'binary',
  134. 'name': '电子发票-%s.xml' % self.name,
  135. 'res_model': 'mail.compose.message',
  136. 'datas': base64.encodebytes(xml_content),
  137. 'company_id': self.company_id.id,
  138. })
  139. self.message_post(attachment_ids=[attachment.id])
  140. # filename = '电子发票-%s.xml' % self.name
  141. # return http.send_file(base64.encodebytes(xml_content), filename=filename, as_attachment=True)
  142. return xml_content
  143. def to_cn_invoice_xml(self):
  144. #清掉已开票,用于生成xml
  145. for line in self.invoice_line_ids:
  146. line.write({
  147. 'is_cn_invoice': False,
  148. })
  149. #开始写xml
  150. Kp = etree.Element('Kp')
  151. self._to_xml_top(Kp)
  152. tree = etree.ElementTree(Kp)
  153. xml_content = etree.tostring(tree, pretty_print=True, encoding="GBK")
  154. attachment = self.env['ir.attachment'].create({
  155. 'type': 'binary',
  156. 'name': '纸质发票-%s.xml' % self.name,
  157. 'res_model': 'mail.compose.message',
  158. 'datas': base64.encodebytes(xml_content),
  159. 'company_id': self.company_id.id,
  160. })
  161. self.message_post(attachment_ids=[attachment.id])
  162. return xml_content
  163. def _to_xml_top(self, Kp):
  164. # 处理xml发票张数
  165. # 处理XML头
  166. Version = etree.SubElement(Kp, 'Version')
  167. Version.text = '3.0'
  168. Fpxx = etree.SubElement(Kp, 'Fpxx')
  169. # 处理xml发票张数
  170. Zsl = etree.SubElement(Fpxx, 'Zsl') # 单据数量
  171. i = 0 #单据数量
  172. invoice = '%s'%(self.name)
  173. amount_top = self.env.company.invoice_top_amount
  174. all_invoiced = False
  175. while not all_invoiced:
  176. # 发票头
  177. if self.move_type == 'out_invoice': #销售发票
  178. fapiao_name = self.partner_id.name
  179. fapiao_vat = self.partner_id.vat
  180. fapiao_address = "%s%s%s %s"%(self.partner_id.city, self.partner_id.street, self.partner_id.street2, self.partner_id.phone)
  181. fapiao_bank = ''
  182. if self.partner_id.bank_ids:
  183. fapiao_bank = '%s %s' % (self.partner_id.bank_ids[0].bank_id.name, self.partner_id.bank_ids[0].acc_number)
  184. if self.move_type == 'in_invoice': #采购发票
  185. fapiao_name = self.env.company.name
  186. fapiao_vat = self.env.company.vat
  187. fapiao_address = "%s%s%s %s" % (
  188. self.env.company.city, self.env.company.street, self.env.company.street2, self.env.company.phone)
  189. fapiao_bank = ''
  190. if self.env.company.bank_ids:
  191. fapiao_bank = '%s %s' % (
  192. self.env.company.bank_ids[0].bank_id.name, self.env.company.bank_ids[0].acc_number)
  193. fapiao_note = self.ref or ''
  194. Fpsj = etree.SubElement(Fpxx, 'Fpsj')
  195. Fp = etree.SubElement(Fpsj, 'Fp')
  196. Djh = etree.SubElement(Fp, 'Djh') # 单据号
  197. Djh.text = invoice
  198. Spbmbbh = etree.SubElement(Fp, 'Spbmbbh') # 商品编码版本号
  199. Spbmbbh.text = '19.0'
  200. Hsbz = etree.SubElement(Fp, 'Hsbz') # 含税标志
  201. Hsbz.text = '0'
  202. Sgbz = etree.SubElement(Fp, 'Sgbz') # 含税标志
  203. Sgbz.text = '0'
  204. Gfmc = etree.SubElement(Fp, 'Gfmc') # 购方名称
  205. Gfmc.text = fapiao_name
  206. Gfsh = etree.SubElement(Fp, 'Gfsh') # 购方税号
  207. Gfsh.text = fapiao_vat
  208. Gfdzdh = etree.SubElement(Fp, 'Gfdzdh') # 购方地址电话
  209. Gfdzdh.text = fapiao_address
  210. Gfyhzh = etree.SubElement(Fp, 'Gfyhzh') # 购方银行帐号
  211. Gfyhzh.text = fapiao_bank
  212. Skr = etree.SubElement(Fp, 'Skr') # 收款人
  213. Skr.text = ''
  214. Fhr = etree.SubElement(Fp, 'Fhr') # 复核人
  215. Fhr.text = ''
  216. Bz = etree.SubElement(Fp, 'Bz') # 备注
  217. Bz.text = fapiao_note
  218. Spxx = etree.SubElement(Fp, 'Spxx')
  219. # 发票明细行
  220. all_invoiced = self._mixi(amount_top, Spxx)
  221. i += 1
  222. Djh.text = '%s%d'%(invoice, i)
  223. Zsl.text = str(i)
  224. def _mixi(self, amount_top, Spxx):
  225. # 明细计算内容,
  226. total_untaxed = i = 0
  227. all_invoiced = True
  228. for line in self.invoice_line_ids:
  229. if len(line.tax_ids.ids) > 1:
  230. raise UserError('多种税率无法开纸质发票!')
  231. if line.is_cn_invoice:
  232. continue
  233. total_untaxed += (line.credit or line.debit)
  234. if (line.credit or line.debit) > amount_top:
  235. raise UserError('系统不支持单行商品金额超上限!')
  236. if total_untaxed > amount_top:
  237. # todo 单行超开票上限拆分多张发票
  238. all_invoiced = False
  239. total_untaxed = total_untaxed - (line.credit or line.debit)
  240. continue
  241. else:
  242. Sph = etree.SubElement(Spxx, 'Sph')
  243. Kce = etree.SubElement(Sph, 'Kce') # 扣除额
  244. Kce.text = ''
  245. Spbm = etree.SubElement(Sph, 'Spbm') # 商品编码
  246. tax_category_id = line.product_id.tax_category_id or line.product_id.categ_id.tax_category_id
  247. if tax_category_id:
  248. Spbm.text = str(tax_category_id.code)
  249. else:
  250. raise UserError('未在产品/产品分类上设置税收编码!')
  251. Dj = etree.SubElement(Sph, 'Dj') # 单价
  252. tax_rate = 0
  253. price = line.price_unit
  254. price_include = False
  255. if line.tax_ids:
  256. tax_rate = round(line.tax_ids[0].amount/100,2)
  257. price_include = line.tax_ids[0].price_include
  258. if price_include:
  259. dj = '%s'%(price/(1+tax_rate/100))
  260. else:
  261. dj = '%s'%(price)
  262. Dj.text = dj
  263. Spmc = etree.SubElement(Sph, 'Spmc') # 商品名称
  264. Spmc.text = line.product_id.name
  265. Ggxh = etree.SubElement(Sph, 'Ggxh') # 规格型号
  266. Ggxh.text = '-'.join([tag.name for tag in line.product_id.product_tag_ids])
  267. Slv = etree.SubElement(Sph, 'Slv') # 税率
  268. Slv.text = '%s'%(tax_rate)
  269. Xh = etree.SubElement(Sph, 'Xh') # 序号
  270. i += 1
  271. Xh.text = '%d'%(i)
  272. Lslbz = etree.SubElement(Sph, 'Lslbz') # 零标识,0出口退税,1免税
  273. Lslbz.text = ''
  274. Syyhzcbz = etree.SubElement(Sph, 'Syyhzcbz') # 优惠政策标识:0不使用,1使用
  275. Syyhzcbz.text = '0'
  276. Sl = etree.SubElement(Sph, 'Sl') # 数量
  277. Sl.text = '%.2f'%(round(line.quantity, 2))
  278. Je = etree.SubElement(Sph, 'Je') # 金额
  279. Je.text = '%.2f'%(round((line.credit or line.debit), 2))
  280. Se = etree.SubElement(Sph, 'Se') # 税额
  281. if tax_rate:
  282. Se.text = '%.2f' % (line.price_total - round((line.credit or line.debit), 2))
  283. else:
  284. Se.text = '0'
  285. Yhzcsm = etree.SubElement(Sph, 'Yhzcsm') # 优惠政策说明
  286. Yhzcsm.text = ''
  287. Qyspbm = etree.SubElement(Sph, 'Qyspbm') # 企业商品编码
  288. Qyspbm.text = ''
  289. Jldw = etree.SubElement(Sph, 'Jldw') # 计量单位
  290. Jldw.text = line.product_uom_id.name
  291. line.write({
  292. 'is_cn_invoice': True,
  293. })
  294. return all_invoiced
  295. def _to_dz_xml_top(self, business):
  296. i = 0 # 单据数量
  297. invoice = '%s' % (self.name)
  298. amount_top = self.env.company.invoice_top_amount
  299. all_invoiced = False
  300. while not all_invoiced:
  301. if self.move_type == 'out_invoice': # 销售发票
  302. fapiao_no = '%s%d' % (invoice, i)
  303. fapiao_name = self.partner_id.name
  304. fapiao_vat = self.partner_id.vat
  305. fapiao_address = "%s%s%s %d" % (
  306. self.partner_id.city, self.partner_id.street, self.partner_id.street2, self.partner_id.phone)
  307. fapiao_bank = ''
  308. if self.partner_id.bank_ids:
  309. fapiao_bank = '%s %s' % (
  310. self.partner_id.bank_ids[0].bank_id.name, self.partner_id.bank_ids[0].acc_number)
  311. fapiao_note = self.ref or ''
  312. company_name = self.env.company.name
  313. company_vat = self.env.company.vat
  314. company_address = "%s%s%s %s" % (
  315. self.env.company.city, self.env.company.street, self.env.company.street2, self.env.company.phone)
  316. company_bank = ''
  317. if self.env.company.bank_ids:
  318. company_bank = '%s %s' % (
  319. self.env.company.bank_ids[0].bank_id.name, self.env.company.bank_ids[0].acc_number)
  320. # 发票头
  321. REQUEST_COMMON_FPKJ = etree.SubElement(business, 'REQUEST_COMMON_FPKJ')
  322. REQUEST_COMMON_FPKJ.set("class", "REQUEST_COMMON_FPKJ")
  323. COMMON_FPKJ_FPT = etree.SubElement(REQUEST_COMMON_FPKJ, 'COMMON_FPKJ_FPT')
  324. COMMON_FPKJ_FPT.set("class", "COMMON_FPKJ_FPT")
  325. FPQQLSH = etree.SubElement(COMMON_FPKJ_FPT, 'FPQQLSH') # 开票请求流水号
  326. FPQQLSH.text = fapiao_no
  327. KPLX = etree.SubElement(COMMON_FPKJ_FPT, 'KPLX') # 开票类型 0为蓝字,1为红字
  328. KPLX.text = '0'
  329. XSF_NSRSBH = etree.SubElement(COMMON_FPKJ_FPT, 'XSF_NSRSBH') # 销售方纳税人识别号
  330. XSF_NSRSBH.text = company_vat
  331. XSF_MC = etree.SubElement(COMMON_FPKJ_FPT, 'XSF_MC') # 销售方名称
  332. XSF_MC.text = company_name
  333. XSF_DZDH = etree.SubElement(COMMON_FPKJ_FPT, 'XSF_DZDH') # 销售方地址、电话
  334. XSF_DZDH.text = company_address
  335. XSF_YHZH = etree.SubElement(COMMON_FPKJ_FPT, 'XSF_YHZH') # 销售方银行帐号
  336. XSF_YHZH.text = company_bank
  337. GMF_NSRSBH = etree.SubElement(COMMON_FPKJ_FPT, 'GMF_NSRSBH') # 购买主纳税人识别号
  338. GMF_NSRSBH.text = fapiao_vat
  339. GMF_MC = etree.SubElement(COMMON_FPKJ_FPT, 'GMF_MC') # 购方名称
  340. GMF_MC.text = fapiao_name
  341. GMF_DZDH = etree.SubElement(COMMON_FPKJ_FPT, 'GMF_DZDH') # 购方地址、电话
  342. GMF_DZDH.text = fapiao_address
  343. GMF_YHZH = etree.SubElement(COMMON_FPKJ_FPT, 'GMF_YHZH') # 购方银行帐号
  344. GMF_YHZH.text = fapiao_bank
  345. KPR = etree.SubElement(COMMON_FPKJ_FPT, 'KPR') # 开票人
  346. KPR.text = ''
  347. SKR = etree.SubElement(COMMON_FPKJ_FPT, 'SKR') # 收款人
  348. SKR.text = ''
  349. FHR = etree.SubElement(COMMON_FPKJ_FPT, 'FHR') # 复核人
  350. FHR.text = ''
  351. YFP_DM = etree.SubElement(COMMON_FPKJ_FPT, 'YFP_DM') # 原发票代码,红字必须
  352. YFP_DM.text = ''
  353. YFP_HM = etree.SubElement(COMMON_FPKJ_FPT, 'YFP_HM') # 原发票号码,红字必须
  354. YFP_HM.text = ''
  355. BZ = etree.SubElement(COMMON_FPKJ_FPT, 'BZ') # 备注
  356. BMB_BBH = etree.SubElement(COMMON_FPKJ_FPT, 'BMB_BBH') # 版本号
  357. BMB_BBH.text = '18.0'
  358. JSHJ = etree.SubElement(COMMON_FPKJ_FPT, 'JSHJ') # 价税合计
  359. HJJE = etree.SubElement(COMMON_FPKJ_FPT, 'HJJE') # 合计金额(不含税)
  360. HJSE = etree.SubElement(COMMON_FPKJ_FPT, 'HJSE') # 合计税额
  361. HSBZ = etree.SubElement(COMMON_FPKJ_FPT, 'HSBZ') # 税率
  362. HJSE.text = '0.00'
  363. COMMON_FPKJ_XMXXS = etree.SubElement(REQUEST_COMMON_FPKJ, 'COMMON_FPKJ_XMXXS')
  364. COMMON_FPKJ_XMXXS.set("class", "COMMON_FPKJ_XMXX")
  365. COMMON_FPKJ_XMXXS.set("size", "1")
  366. # 发票明细行
  367. all_invoiced = self._dzmixi(COMMON_FPKJ_XMXXS, amount_top)
  368. BZ.text = fapiao_note
  369. HJJE.text = '%.2f'%self.amount_untaxed_signed
  370. JSHJ.text = '%.2f'%self.amount_total_signed
  371. HJSE.text = '%.2f'%(self.amount_total_signed - self.amount_untaxed_signed)
  372. HSBZ.text = '0'
  373. def _dzmixi(self, COMMON_FPKJ_XMXXS, amount_top):
  374. total_untaxed = 0
  375. all_invoiced = True
  376. for line in self.invoice_line_ids:
  377. if len(line.tax_ids.ids) > 1:
  378. raise UserError('多种税率无法开纸质发票!')
  379. if line.is_cn_invoice:
  380. continue
  381. total_untaxed += (line.credit or line.debit)
  382. if (line.credit or line.debit) > amount_top:
  383. raise UserError('系统不支持单行商品金额超上限!')
  384. if total_untaxed > amount_top:
  385. # todo 单行超开票上限拆分多张发票
  386. all_invoiced = False
  387. total_untaxed = total_untaxed - (line.credit or line.debit)
  388. continue
  389. else:
  390. amount = (line.credit or line.debit) # 成交人民币
  391. COMMON_FPKJ_XMXX = etree.SubElement(COMMON_FPKJ_XMXXS, 'COMMON_FPKJ_XMXX')
  392. FPHXZ = etree.SubElement(COMMON_FPKJ_XMXX, 'FPHXZ') # 发票行性质,0正常行,1折扣行,2被折扣行
  393. FPHXZ.text = '0'
  394. XMMC = etree.SubElement(COMMON_FPKJ_XMXX, 'XMMC') # 商品名称
  395. XMMC.text = line.product_id.name
  396. GGXH = etree.SubElement(COMMON_FPKJ_XMXX, 'GGXH') # 规格型号
  397. GGXH.text = '-'.join([tag.name for tag in line.product_id.product_tag_ids])
  398. DW = etree.SubElement(COMMON_FPKJ_XMXX, 'DW') # 计量单位
  399. DW.text = line.product_uom_id.name
  400. SPBM = etree.SubElement(COMMON_FPKJ_XMXX, 'SPBM') # 税收编码
  401. tax_category_id = line.product_id.tax_category_id or line.product_id.categ_id.tax_category_id
  402. if tax_category_id:
  403. SPBM.text = str(tax_category_id.code)
  404. else:
  405. raise UserError('未在产品/产品分类上设置税收编码!')
  406. ZXBM = etree.SubElement(COMMON_FPKJ_XMXX, 'ZXBM') # 企业编码
  407. ZXBM.text = ''
  408. YHZCBS = etree.SubElement(COMMON_FPKJ_XMXX, 'YHZCBS') # 优惠政策标识:0不使用,1使用
  409. YHZCBS.text = '0'
  410. LSLBS = etree.SubElement(COMMON_FPKJ_XMXX, 'LSLBS') # 零标识,0出口退税,1免税
  411. ZZSTSGL = etree.SubElement(COMMON_FPKJ_XMXX, 'ZZSTSGL') # 优惠政策说明??
  412. XMSL = etree.SubElement(COMMON_FPKJ_XMXX, 'XMSL') # 数量
  413. XMSL.text = '%.2f'%(round(line.quantity, 2))
  414. XMDJ = etree.SubElement(COMMON_FPKJ_XMXX, 'XMDJ') # 单价
  415. tax_rate = 0
  416. price = line.price_unit
  417. price_include = False
  418. if line.tax_ids:
  419. tax_rate = round(line.tax_ids[0].amount / 100, 2)
  420. price_include = line.tax_ids[0].price_include
  421. if price_include:
  422. dj = '%s' % (price / (1 + tax_rate / 100))
  423. else:
  424. dj = '%s' % (price)
  425. XMDJ.text = dj
  426. XMJE = etree.SubElement(COMMON_FPKJ_XMXX, 'XMJE') # 金额
  427. XMJE.text = '%.2f'%(round((line.credit or line.debit), 2))
  428. SE = etree.SubElement(COMMON_FPKJ_XMXX, 'SE') # 税额
  429. if tax_rate:
  430. SE.text = '%.2f' % (line.price_total - round((line.credit or line.debit), 2))
  431. else:
  432. SE.text = '0'
  433. SL = etree.SubElement(COMMON_FPKJ_XMXX, 'SL') # 税率
  434. SL.text = '%s'%(tax_rate)
  435. KCE = etree.SubElement(COMMON_FPKJ_XMXX, 'KCE') # 扣除额
  436. KCE.text = '0'
  437. return all_invoiced
  438. class AccountToCnInvoice(models.TransientModel):
  439. _name = 'account.to.cn.invoice'
  440. _description = '开发票'
  441. name = fields.Char('File Name', readonly=True)
  442. is_new_type = fields.Boolean('开全电发票', default=True)
  443. cn_invoice_type = fields.Many2one('cn.invoice.type', string='发票类型')
  444. data = fields.Binary('File', readonly=True, attachment=False)
  445. img = fields.Binary('图片', attachment=True)
  446. is_updata = fields.Boolean('开始上传', default=True)
  447. state = fields.Selection([('draft', 'draft'), ('done', 'done'), ('end', 'end')], default='draft')
  448. def export_excel(self):
  449. pass
  450. def invoice_updata(self):
  451. pass
  452. def confirm_updata(self):
  453. pass
  454. def act_getfile(self):
  455. invoice_ids = self.env['account.move'].browse(self._context.get('active_ids'))
  456. stream = io.BytesIO()
  457. with zipfile.ZipFile(stream, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as doc_zip:
  458. i = 1
  459. for invoice in invoice_ids:
  460. if self.cn_invoice_type.code in ['zp', 'pp']:
  461. invoice_xml = invoice.to_cn_invoice_xml()
  462. name = '纸质发票/%s.xml' % invoice.name.replace('/', '-')
  463. elif self.cn_invoice_type.code in ['dzzp', 'dzfp']:
  464. invoice_xml = invoice.to_cn_invoice_dz_xml()
  465. name = '电子发票/%s.xml' % invoice.name.replace('/', '-')
  466. doc_zip.writestr(name, invoice_xml)
  467. i += 1
  468. name = "%s.zip" % (date.today())
  469. self.write({
  470. 'data': base64.encodebytes(stream.getvalue()),
  471. 'name': name,
  472. 'state': 'done',
  473. })
  474. return {
  475. 'type': 'ir.actions.act_window',
  476. 'res_model': 'account.to.cn.invoice',
  477. 'view_mode': 'form',
  478. 'res_id': self.id,
  479. 'views': [(False, 'form')],
  480. 'target': 'new',
  481. }
上海开阖软件有限公司 沪ICP备12045867号-1