Commit 4a8eb5e9 authored by Lingnan Wu's avatar Lingnan Wu Committed by Romain Courteaud

change the invoice ODT template to separate the tax and the products.

parent 21fae277
...@@ -132,9 +132,20 @@ def getTaxLineList(order):\n ...@@ -132,9 +132,20 @@ def getTaxLineList(order):\n
return tax_line_list\n return tax_line_list\n
\n \n
\n \n
\n
line_base_contribution_list = []\n
number = 0\n
line_novat_totalprice = 0\n
line_list = []\n line_list = []\n
line_not_vat = []\n
line_vat = []\n
line_not_vat_has_no_vat = {}\n
total_price = 0.0\n total_price = 0.0\n
total_vat = 0.0\n total_vat = 0.0\n
total_vat_price = 0.0\n
vat_total_list = []\n
taxnumber = 0\n
taxname = \'\'\n
\n \n
def unicodeDict(d):\n def unicodeDict(d):\n
for k, v in d.items():\n for k, v in d.items():\n
...@@ -176,8 +187,23 @@ for line in getSubLineList(context):\n ...@@ -176,8 +187,23 @@ for line in getSubLineList(context):\n
display_id = \'translated_title\'\n display_id = \'translated_title\'\n
if request.get(\'international_form\'):\n if request.get(\'international_form\'):\n
display_id = \'title\'\n display_id = \'title\'\n
desc = (\', \'.join([x[0] for x in\n desc = (\', \'.join([x[0] for x in line.getVariationCategoryItemList(display_id=display_id)]),)\n
line.getVariationCategoryItemList(display_id=display_id)]),)\n is_vat=0\n
portal_preferences = context.getPortalObject().portal_preferences\n
if portal_preferences.getPreferredTaxUseList()==[] :\n
vat="use/trade/tax"\n
is_vat=line.isMemberOf(vat) \n
else:\n
vatlist=portal_preferences.getPreferredTaxUseList() \n
for vat in vatlist:\n
is_vat = is_vat or line.isMemberOf(vat)\n
if not is_vat:\n
if line.getBaseContribution() not in line_base_contribution_list:\n
line_base_contribution_list.append(line.getBaseContribution())\n
taxnumber=line_base_contribution_list.index(line.getBaseContribution())+1\n
else:\n
taxname=line.getBaseContribution()\n
\n
line_dict = {\n line_dict = {\n
\'style_name\': \'Table_20_Contents\',\n \'style_name\': \'Table_20_Contents\',\n
\'left_style_name\': \'Table_20_Contents_20_Left\',\n \'left_style_name\': \'Table_20_Contents_20_Left\',\n
...@@ -187,16 +213,44 @@ for line in getSubLineList(context):\n ...@@ -187,16 +213,44 @@ for line in getSubLineList(context):\n
\'reference\': line.getResource() is not None\\\n \'reference\': line.getResource() is not None\\\n
and line.getResourceValue().getReference() or \'\',\n and line.getResourceValue().getReference() or \'\',\n
\'description\': desc,\n \'description\': desc,\n
\'base_contribution\':line.getBaseContribution() or None,\n
\'use_type\':line.getResourceValue().getUse() or \'\',\n
\'use_type_tax\':is_vat,\n
\'total_quantity\': line.getTotalQuantity() or \'\',\n \'total_quantity\': line.getTotalQuantity() or \'\',\n
\'tax_name\':taxname or \'\',\n
\'tax_number\':taxnumber or \'\',\n
\'quantity_unit\': line.getQuantityUnitTranslatedTitle() or (\n \'quantity_unit\': line.getQuantityUnitTranslatedTitle() or (\n
line.getResource() and line.getResourceValue().getQuantityUnitTranslatedTitle()) or \'\',\n line.getResource() and line.getResourceValue().getQuantityUnitTranslatedTitle()) or \'\',\n
\'stop_date\': getOrderedDate(line.getStopDate()) or \'\',\n \'stop_date\': getOrderedDate(line.getStopDate()) or \'\',\n
\'base_price\': line.getPrice() or \'\',\n \'base_price\': line.getPrice() or \'\',\n
\'total_price\': line.getTotalPrice() or \'\',\n \'total_price\': line.getTotalPrice() or 0,\n
\'specialise_title\' : line.getProperty(\'specialise_title\', \'\'),\n \'specialise_title\' : line.getProperty(\'specialise_title\', \'\'),\n
}\n }\n
\n
if line_dict[\'use_type_tax\']:\n
total_vat_price+=line.getTotalPrice() or 0.0\n
line_vat.append(unicodeDict(line_dict.copy()))\n
else:\n
total_price += line.getTotalPrice() or 0.0\n total_price += line.getTotalPrice() or 0.0\n
line_not_vat.append(unicodeDict(line_dict.copy()))\n
if line_dict[\'base_contribution\'] is None:\n
line_novat_totalprice = line_novat_totalprice + line_dict[\'total_price\']\n
line_not_vat_has_no_vat = {\n
\'tax_name\': None ,\n
\'total_quantity\': line_novat_totalprice,\n
\'base_price\': 0.00 ,\n
\'total_price\': 0.00 ,\n
}\n
line_list.append(unicodeDict(line_dict.copy()))\n line_list.append(unicodeDict(line_dict.copy()))\n
if line_not_vat_has_no_vat != {} :\n
line_vat.append(unicodeDict(line_not_vat_has_no_vat.copy()))\n
for line_each in line_vat:\n
if line_each[\'tax_name\'] in line_base_contribution_list :\n
vatNumber=line_base_contribution_list.index(line_each[\'tax_name\'])+1\n
else:\n
vatNumber=0\n
line_each.update({\'vat_number\': vatNumber})\n
line_vat.sort(key=lambda obj:obj.get(\'vat_number\'))\n
\n \n
inch_cm_ratio = 2.54 / 100.0\n inch_cm_ratio = 2.54 / 100.0\n
\n \n
...@@ -397,11 +451,15 @@ data_dict = {\n ...@@ -397,11 +451,15 @@ data_dict = {\n
\'delivery_mode\': context.getDeliveryModeTranslatedTitle() or \'\',\n \'delivery_mode\': context.getDeliveryModeTranslatedTitle() or \'\',\n
\'incoterm\': context.getIncoterm() and context.getIncotermValue().getCodification() or \'\',\n \'incoterm\': context.getIncoterm() and context.getIncotermValue().getCodification() or \'\',\n
\n \n
\'vat_name_list\':line_base_contribution_list,\n
\'total_price\':total_price+total_vat_price,\n
\'total_price_novat\': total_price,\n \'total_price_novat\': total_price,\n
\'vat_list\': getTaxLineList(context),\n \'vat_list\': total_vat,\n
\'vat_total_price\':total_vat_price,\n
\'description\': getFieldAsLineList(context.getDescription()),\n \'description\': getFieldAsLineList(context.getDescription()),\n
\'specialise_title\': context.getProperty(\'specialise_title\',\'\'),\n \'specialise_title\': context.getProperty(\'specialise_title\',\'\'),\n
\n \'line_vat\':line_vat,\n
\'line_not_vat\':line_not_vat,\n
\'line_list\': line_list,\n \'line_list\': line_list,\n
}\n }\n
\n \n
......
...@@ -211,7 +211,8 @@ system_prefs = dict(\n ...@@ -211,7 +211,8 @@ system_prefs = dict(\n
preferred_client_role_list = [\'client\'],\n preferred_client_role_list = [\'client\'],\n
preferred_sale_use_list = [\'trade/sale\'],\n preferred_sale_use_list = [\'trade/sale\'],\n
preferred_purchase_use_list = [\'trade/purchase\'],\n preferred_purchase_use_list = [\'trade/purchase\'],\n
preferred_packing_use_list = [\'trade/container\'])\n preferred_packing_use_list = [\'trade/container\'],\n
preferred_tax_use_list=[\'trade/tax\'])\n
\n \n
configuration_save.addConfigurationItem(\n configuration_save.addConfigurationItem(\n
\'System Preference Configurator Item\',\n \'System Preference Configurator Item\',\n
......
...@@ -367,6 +367,7 @@ class StandardConfigurationMixin(TestLiveConfiguratorWorkflowMixin): ...@@ -367,6 +367,7 @@ class StandardConfigurationMixin(TestLiveConfiguratorWorkflowMixin):
self.assertEquals(['trade/sale'], preference_tool.getPreferredSaleUseList()) self.assertEquals(['trade/sale'], preference_tool.getPreferredSaleUseList())
self.assertEquals(['trade/purchase'], preference_tool.getPreferredPurchaseUseList()) self.assertEquals(['trade/purchase'], preference_tool.getPreferredPurchaseUseList())
self.assertEquals(['trade/container'], preference_tool.getPreferredPackingUseList()) self.assertEquals(['trade/container'], preference_tool.getPreferredPackingUseList())
self.assertEquals(['trade/tax']), preference_tool.getPreferredTaxUseList())
def stepCheckModulesBusinessApplication(self, sequence=None, sequence_list=None, **kw): def stepCheckModulesBusinessApplication(self, sequence=None, sequence_list=None, **kw):
""" """
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -303,6 +303,7 @@ ...@@ -303,6 +303,7 @@
<string>my_view_mode_preferred_internal_use_list</string> <string>my_view_mode_preferred_internal_use_list</string>
<string>my_view_mode_listbox_read_only_effective_date</string> <string>my_view_mode_listbox_read_only_effective_date</string>
<string>my_view_mode_listbox_read_only_expiration_date</string> <string>my_view_mode_listbox_read_only_expiration_date</string>
<string>my_view_mode_preferred_tax_use_list</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>items</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_view_mode_preferred_tax_use_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_multi_list_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Tax Uses</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: getattr(here.portal_categories.use, preferences.getPreference(\'preferred_category_child_item_list_method_id\', \'getCategoryChildCompactLogicalPathItemList\'))(base=1, local_sort_id=(\'int_index\', \'translated_title\'), checked_permission=\'View\')</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -96,6 +96,7 @@ ...@@ -96,6 +96,7 @@
<string>my_preferred_supplier_role_list</string> <string>my_preferred_supplier_role_list</string>
<string>my_preferred_client_role_list</string> <string>my_preferred_client_role_list</string>
<string>my_preferred_trade_base_amount_list</string> <string>my_preferred_trade_base_amount_list</string>
<string>my_preferred_tax_use_list</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_preferred_tax_use_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_preferred_tax_use_list</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewTradeFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/lines</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Uses of taxes</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>preferred_tax_use_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>preference</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: []</string> </value>
</item>
<item>
<key> <string>write_permission</string> </key>
<value> <string>Manage properties</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
Tests invoice creation from simulation. Tests invoice creation from simulation.
""" """
import sys, zipfile, xml.dom.minidom
import StringIO
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.tests.utils import FileUpload, DummyMailHost from Products.ERP5Type.tests.utils import FileUpload, DummyMailHost
...@@ -1609,12 +1611,15 @@ class TestInvoice(TestInvoiceMixin): ...@@ -1609,12 +1611,15 @@ class TestInvoice(TestInvoiceMixin):
self.assertEquals(DateTime(2002, 03, 04), self.assertEquals(DateTime(2002, 03, 04),
invoice_transaction_movement.getStopDate()) invoice_transaction_movement.getStopDate())
def test_Invoice_viewAsODT(self): def test_Invoice_viewAsODT(self):
resource = self.portal.getDefaultModule( resource = self.portal.getDefaultModule(
self.resource_portal_type).newContent( self.resource_portal_type).newContent(
portal_type=self.resource_portal_type, portal_type=self.resource_portal_type,
title='Resource',) title='Resource',)
resource_tax = self.portal.getDefaultModule(
self.resource_portal_type).newContent(
portal_type=self.resource_portal_type,
title='Resource Tax',)
client = self.portal.organisation_module.newContent( client = self.portal.organisation_module.newContent(
portal_type='Organisation', title='Client') portal_type='Organisation', title='Client')
vendor = self.portal.organisation_module.newContent( vendor = self.portal.organisation_module.newContent(
...@@ -1628,14 +1633,78 @@ class TestInvoice(TestInvoiceMixin): ...@@ -1628,14 +1633,78 @@ class TestInvoice(TestInvoiceMixin):
source_section_value=vendor, source_section_value=vendor,
destination_value=client, destination_value=client,
destination_section_value=client) destination_section_value=client)
line = invoice.newContent(portal_type=self.invoice_line_portal_type, product_line1 = invoice.newContent(portal_type=self.invoice_line_portal_type,
resource_value=resource, resource_value=resource,
quantity=10, quantity=10,
base_contribution='tax1',
price=3) price=3)
product_line2 = invoice.newContent(portal_type=self.invoice_line_portal_type,
resource_value=resource,
quantity=20,
base_contribution='tax1',
price=5)
product_line3 = invoice.newContent(portal_type=self.invoice_line_portal_type,
resource_value=resource,
quantity=60,
base_contribution='tax2',
price=5)
product_line4 = invoice.newContent(portal_type=self.invoice_line_portal_type,
resource_value=resource,
quantity=60,
price=3)
product_line5 = invoice.newContent(portal_type=self.invoice_line_portal_type,
resource_value=resource,
quantity=7,
price=20)
tax_line1 = invoice.newContent(portal_type=self.invoice_line_portal_type,
resource_value=resource_tax,
use='trade/tax',
base_contribution='tax1',
quantity=130,
price=0.2)
tax_line2 = invoice.newContent(portal_type=self.invoice_line_portal_type,
resource_value=resource_tax,
use='trade/tax',
base_contribution='tax2',
quantity=300,
price=0.05)
tax_line3 = invoice.newContent(portal_type=self.invoice_line_portal_type,
resource_value=resource_tax,
use='trade/tax',
base_contribution='tax3',
quantity=20,
price=0.1)
invoice.confirm() invoice.confirm()
self.tic() self.tic()
odt = invoice.Invoice_viewAsODT() odt = invoice.Invoice_viewAsODT()
import cStringIO
output = cStringIO.StringIO()
output.write(odt)
m = OpenDocumentTextFile(output)
text_content=m.toString().encode('ascii','replace')
if text_content.find('Resource Tax') != -1 :
self.fail('fail to delete the vat line in product line')
if text_content.find('Vat Code') == -1 :
self.fail('fail to add the vat code')
if text_content.find('Amount') == -1 :
self.fail('fail to add the amount for each tax')
if text_content.find('Rate') == -1 :
self.fail('fail to add the Rate for each tax')
tax1_product_total_price=str(10*3+20*5)
if text_content.find(tax1_product_total_price) == -1 :
self.fail('fail to get the total price of products which tax1')
tax2_product_total_price=str(60*5)
if text_content.find(tax2_product_total_price) == -1 :
self.fail('fail to get the total price of products which tax2')
no_tax_product_total_price=str(60*3+7*20)
if text_content.find(no_tax_product_total_price) == -1 :
self.fail('fail to get the total price of products which have no tax')
product_total_price_no_tax=str(10*3+20*5+60*5+60*3+7*20)
if text_content.find(product_total_price_no_tax) == -1 :
self.fail('fail to get the total price of the products without tax')
product_total_price=str(10*3+20*5+60*5+60*3+7*20+130*0.2+300*0.05+20*0.1)
if text_content.find(product_total_price) == -1 :
self.fail('fail to get the total price of the products with tax')
from Products.ERP5OOo.tests.utils import Validator from Products.ERP5OOo.tests.utils import Validator
odf_validator = Validator() odf_validator = Validator()
err_list = odf_validator.validate(odt) err_list = odf_validator.validate(odt)
...@@ -3537,6 +3606,28 @@ class TestPurchaseInvoice(TestInvoice, ERP5TypeTestCase): ...@@ -3537,6 +3606,28 @@ class TestPurchaseInvoice(TestInvoice, ERP5TypeTestCase):
stepTic stepTic
""" """
class OpenDocumentTextFile :
def __init__ (self, filelikeobj) :
zip = zipfile.ZipFile(filelikeobj)
self.content = xml.dom.minidom.parseString(zip.read("content.xml"))
def toString (self) :
""" Converts the document to a string. """
buffer = u""
for val in ["text:p", "text:h", "text:list"]:
for paragraph in self.content.getElementsByTagName(val) :
buffer += self.textToString(paragraph) + "\n"
return buffer
def textToString(self, element) :
buffer = u""
for node in element.childNodes :
if node.nodeType == xml.dom.Node.TEXT_NODE :
buffer += node.nodeValue
elif node.nodeType == xml.dom.Node.ELEMENT_NODE :
buffer += self.textToString(node)
return buffer
import unittest import unittest
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment