From 1adc3c7864a6d295513e73863dac9d8a8fb3ec0e Mon Sep 17 00:00:00 2001 From: "watcha.h" Date: Wed, 22 Apr 2015 23:02:31 +0700 Subject: [PATCH] fix Issue #848 --- .../layouts/clinic_tax_rate_form.xml | 17 +++ netforce_clinic/models/__init__.py | 3 + .../models/account_tax_component.py | 29 ++++++ netforce_clinic/models/num2word.py | 85 +++++++++++++++ .../models/report_thai_wht_certif.py | 97 ++++++++++++++++++ .../reports/report_labor_cost.xlsx | Bin 0 -> 6941 bytes .../templates/report_labor_cost.hbs | 1 + 7 files changed, 232 insertions(+) create mode 100644 netforce_clinic/layouts/clinic_tax_rate_form.xml create mode 100644 netforce_clinic/models/account_tax_component.py create mode 100644 netforce_clinic/models/num2word.py create mode 100644 netforce_clinic/models/report_thai_wht_certif.py create mode 100644 netforce_clinic/reports/report_labor_cost.xlsx diff --git a/netforce_clinic/layouts/clinic_tax_rate_form.xml b/netforce_clinic/layouts/clinic_tax_rate_form.xml new file mode 100644 index 0000000..74483a9 --- /dev/null +++ b/netforce_clinic/layouts/clinic_tax_rate_form.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/netforce_clinic/models/__init__.py b/netforce_clinic/models/__init__.py index d4e1fa4..cdbc078 100644 --- a/netforce_clinic/models/__init__.py +++ b/netforce_clinic/models/__init__.py @@ -128,3 +128,6 @@ from . import compute_labor_cost from . import login from . import sequence from . import report_shop +from . import account_tax_component +from . import report_thai_wht_certif +from . import num2word diff --git a/netforce_clinic/models/account_tax_component.py b/netforce_clinic/models/account_tax_component.py new file mode 100644 index 0000000..3350c00 --- /dev/null +++ b/netforce_clinic/models/account_tax_component.py @@ -0,0 +1,29 @@ +from netforce.model import Model, fields + +class TaxComponent(Model): + _inherit="account.tax.component" + _fields={ + "sequence": fields.Selection([ + ["1","1"], + ["2","2"], + ["3","3"], + ["4","4"], + ["4.1.1","4.1.1"], + ["4.1.2","4.1.2"], + ["4.1.3","4.1.3"], + ["4.1.4","4.1.4"], + ["4.2.1","4.2.1"], + ["4.2.2","4.2.2"], + ["4.2.3","4.2.3"], + ["4.2.4","4.2.4"], + ["4.2.5","4.2.5"], + ["5","5"], + ["6","6"], + ],"Sequence"), #report sequence + } + + _defaults={ + 'sequence': 5, + } + +TaxComponent.register() diff --git a/netforce_clinic/models/num2word.py b/netforce_clinic/models/num2word.py new file mode 100644 index 0000000..28a51aa --- /dev/null +++ b/netforce_clinic/models/num2word.py @@ -0,0 +1,85 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +sym={ + "en": { + "sep": " ", + "0": "zero", + "x": ["one","two","three","four","five" ,"six","seven","eight","nine"], + "1x": ["ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"], + "x0": ["twenty","thirty","fourty","fifty","sixty","seventy","eighty","ninety"], + "100": "hundred", + "1K": "thousand", + "1M": "million", + }, + "th": { + "sep": "", + "0": "ศูนย์", + "x": ["หนึ่ง","สอง","สาม","สี่","ห้า" ,"หก","เจ็ด","แปด","เก้า"], + "x0": ["สิบ","ยี่สิบ","สามสิบ","สี่สิบ","ห้าสิบ","หกสิบ","เจ็ดสิบ","แปดสิบ","เก้าสิบ"], + "x1": "เอ็ด", + "100": "ร้อย", + "1K": "พัน", + "10K": "หมื่น", + "100K": "แสน", + "1M":"ล้าน", + } +} + +def num2word(n,l="en"): + #TODO:Support Thai Stang + if n==0: + return sym[l]["0"] + " " + elif n<10: + return sym[l]["x"][n-1] + elif n<100: + if l=="en": + if n<20: + return sym[l]["1x"][n-10] + else: + return sym[l]["x0"][n//10-2]+(n%10 and sym[l]["sep"]+num2word(n%10,l) or "") + elif l=="th": + return sym[l]["x0"][n//10-1]+(n%10 and (n%10==1 and sym[l]["x1"] or sym[l]["x"][n%10-1]) or "") + elif n<1000: + return sym[l]["x"][n//100-1]+sym[l]["sep"]+sym[l]["100"]+(n%100 and sym[l]["sep"]+num2word(n%100,l) or "") + + elif n<1000000: + if l=="en": + return num2word(n/1000,l)+sym[l]["sep"]+sym[l]["1K"]+(n%1000 and sym[l]["sep"]+num2word(n%1000,l) or "") + elif l=="th": + if n<10000: + return sym[l]["x"][n//1000-1]+sym[l]["1K"]+(n%1000 and num2word(n%1000,l) or "") + elif n<100000: + print(">>>>>",n) + return sym[l]["x"][n//10000-1]+sym[l]["10K"]+(n%10000 and num2word(n%10000,l) or "") + else: + return sym[l]["x"][n//100000-1]+sym[l]["100K"]+(n%100000 and num2word(n%100000,l) or "") + elif n<1000000000: + return num2word(n//1000000,l)+sym[l]["sep"]+sym[l]["1M"]+sym[l]["sep"]+(n%1000000 and num2word(n%1000000,l) or "") + else: + return "N/A" + +def num2word_th(n,l="th"): + base=0 + end=0 + number = n + if type(n) == type(''): + number=float(n) + word = '' + if type(number) in (type(0),type(0.0)): + number = ('%.2f'%number).split('.') + base = num2word(int(number[0]),l=l) + if int(number[1])!=0: + end = num2word(int(number[1]),l=l) + if base==0 and end==0: + word='ศุนย์บาทถ้วน' + if base!=0 and end==0: + word=base+'บาทถ้วน' + if base!=0 and end!=0: + word=base+'บาท'+end+'สตางค์' + return word + +if __name__ == '__main__': + import sys + n=sys.stdin.readline() + #print num2word_th(n) diff --git a/netforce_clinic/models/report_thai_wht_certif.py b/netforce_clinic/models/report_thai_wht_certif.py new file mode 100644 index 0000000..8f6ceb7 --- /dev/null +++ b/netforce_clinic/models/report_thai_wht_certif.py @@ -0,0 +1,97 @@ +from netforce.model import Model, fields, get_model +from datetime import * +from dateutil.relativedelta import * +from netforce.access import get_active_company +from . import num2word + +def fmt_thai_tax_no(tax_no): + s=tax_no or "" + s.replace("-","") + if len(s)<13: + s+=" "*(13-len(s)) + return s + +class ReportThaiWHTCertif(Model): + _inherit="report.thai.wht.certif" + + def get_report_data(self,ids,context={}): + if not ids: + return {} + obj=self.browse(ids)[0] + company_id=get_active_company() + comp=get_model("company").browse(company_id) + settings=get_model("settings").browse(1) + pmt=obj.payment_id + contact=pmt.partner_id + data={ + "company_tax_no": fmt_thai_tax_no(settings.tax_no), + "company_name": comp.name, + "dept_addr": settings.default_address_id.address_text.replace("\n",", "), # XXX + "tax_no": fmt_thai_tax_no(contact.tax_no), + "partner_name": contact.name, + "partner_addr": contact.default_address_id.address_text.replace("\n",", ") if contact.default_address_id else None, # XXX + "date": datetime.strptime(pmt.date,"%Y-%m-%d").strftime("%d/%m/%Y"), + "lines": [{}], # XXX + } + move=pmt.move_id + if not move: + raise Exception("Journal entry not found") + base={} + tax={} + contact_type=None + wht_no=None + for line in move.lines: + comp=line.tax_comp_id + if not comp: + continue + if comp.type!="wht" or comp.trans_type!="in": + continue + if not wht_no: + wht_no=line.tax_no + else: + if wht_no!=line.tax_no: + raise Exception("Multiple WHT numbers for same payment") + if not contact_type: + contact_type=comp.contact_type + else: + if contact_type!=comp.contact_type: + raise Exception("Different WHT contact types for same payment") + print('sequence ', comp.sequence) + exp_code=comp.sequence or "5" + #if comp.exp_type=="salary": + #exp_code="1" + #elif comp.exp_type=="commission": + #exp_code="2" + #elif comp.exp_type=="royalty": + #exp_code="3" + #elif comp.exp_type=="interest": + #exp_code="4" + #elif comp.exp_type in ("rental","service","transport","advert"): + #exp_code="5" + #else: + #exp_code="6" + if exp_code=="6": + data["desc"]=comp.description + base.setdefault(exp_code,0) + tax.setdefault(exp_code,0) + base[exp_code]+=line.tax_base + tax[exp_code]+=line.credit-line.debit + if not wht_no: + raise Exception("WHT number not found") + data["number"]=wht_no + if contact_type=="individual": + data["num_user1"]="x" + data["num_user2"]="" + elif contact_type=="company": + data["num_user1"]="" + data["num_user2"]="x" + for exp_code,amt in base.items(): + data["amt_"+exp_code]=amt + for exp_code,amt in tax.items(): + data["tax_"+exp_code]=amt + data["sum_amt"]=sum(base.values()) + data["sum_tax"]=sum(tax.values()) + data["total_word"]=num2word.num2word_th(data["sum_tax"],l='th') + return data + +ReportThaiWHTCertif.register() diff --git a/netforce_clinic/reports/report_labor_cost.xlsx b/netforce_clinic/reports/report_labor_cost.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..87e827a13ea3dc59994dad94bf375c5f38283773 GIT binary patch literal 6941 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 N>IFyb6{%kf|37(c*Qo#i literal 0 HcmV?d00001 diff --git a/netforce_clinic/templates/report_labor_cost.hbs b/netforce_clinic/templates/report_labor_cost.hbs index 84ffe7e..75c337d 100644 --- a/netforce_clinic/templates/report_labor_cost.hbs +++ b/netforce_clinic/templates/report_labor_cost.hbs @@ -1,6 +1,7 @@

จาก {{date_from}} ถึง {{date_to}} +

{{#ifeq report_type "detail"}}