Compare commits

...

2 Commits

Author SHA1 Message Date
Torsten Ueberschar
b8bd3f288b take PricePerUnit from customer if not set in invoice position 2024-02-19 10:12:52 +01:00
Torsten Ueberschar
6f1120c8b4 remove .idea 2024-02-19 09:22:25 +01:00
10 changed files with 24 additions and 184 deletions

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml generated
View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.10 (freelance_invoice)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (freelance_invoice)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/freelance_invoice.iml" filepath="$PROJECT_DIR$/.idea/freelance_invoice.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

132
.idea/workspace.xml generated
View File

@@ -1,132 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="7672063a-a324-4a9c-a8d3-c38955c8d763" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/freelance_invoice.iml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/inspectionProfiles/profiles_settings.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/modules.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
<change afterPath="$PROJECT_DIR$/setup.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/invoice_generator/__init__.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/invoice_generator/html_generator.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/test_data/RG004711.yaml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/test_data/envelope.yaml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/test_data/templates/invoice.html" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ChangesViewManager">
<option name="groupingKeys">
<option value="directory" />
</option>
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Python Script" />
<option value="HTML File" />
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProjectColorInfo"><![CDATA[{
"associatedIndex": 1
}]]></component>
<component name="ProjectId" id="2c21ZczAqxeYNrytEGCIucesn9A" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"DefaultHtmlFileTemplate": "HTML File",
"Python.main.executor": "Run",
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"git-widget-placeholder": "master",
"last_opened_file_path": "/home/torsten/PycharmProjects/freelance_invoice/test_data",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"settings.editor.selected.configurable": "preferences.pluginManager",
"vue.rearranger.settings.migration": "true"
}
}]]></component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/test_data" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/src" />
</key>
</component>
<component name="RunManager">
<configuration name="main" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
<module name="freelance_invoice" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/main.py" />
<option name="PARAMETERS" value="--invoice RG004711 --base test_data/ --template ./test_data/templates/" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
</component>
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="bundled-python-sdk-5a2391486177-2887949eec09-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-233.13763.11" />
</set>
</attachedChunks>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="7672063a-a324-4a9c-a8d3-c38955c8d763" name="Changes" comment="" />
<created>1707294915620</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1707294915620</updated>
<workItem from="1707294917219" duration="20842000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="com.intellij.coverage.CoverageDataManagerImpl">
<SUITE FILE_PATH="coverage/freelance_invoice$main.coverage" NAME="main Coverage Results" MODIFIED="1707321806053" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
</component>
</project>

View File

@@ -32,8 +32,7 @@ class HtmlTemplate:
@staticmethod
def calculate_total(invoice_data):
return sum(
(pos['Quantity'] * (pos['PricePerUnit'] or invoice_data.PricePerUnit)) for pos in invoice_data.Positions)
return sum((pos['Quantity'] * pos['PricePerUnit']) for pos in invoice_data.Positions)
@staticmethod
def named_replace(value, **replacements):

View File

@@ -86,13 +86,16 @@ def main():
print('Envelope data:')
envelope_data = DataObject(**envelope)
print(envelope_data.__dict__)
print('<--->')
print(yaml.dump(envelope_data))
print('</--->')
print('Invoice data:')
invoice_data = DataObject(**invoice)
merge_envelope_data_into_invoice_data(invoice_data, envelope_data.Invoice)
selected_customer = next((x for x in envelope_data.Customers if x['CustomerId'] == invoice_data.CustomerId), None)
selected_customer = next((x for x in envelope_data.Customers if x['CustomerId'] == invoice_data.CustomerId),
None)
merge_envelope_data_into_invoice_data(invoice_data, selected_customer)
if not hasattr(invoice_data, 'InvoiceDate'):
@@ -103,8 +106,17 @@ def main():
if not hasattr(invoice_data, 'Id'):
invoice_data.Id = None
if not hasattr(invoice_data, 'Positions'):
invoice_data.Positions = []
for position in invoice_data.Positions:
if 'PricePerUnit' not in position or position['PricePerUnit'] is None:
position['PricePerUnit'] = invoice_data.PricePerUnit
invoice_data.Id = invoice_data.Id or invoice_file.stem
print(invoice_data.__dict__)
print('<--->')
print(yaml.dump(invoice_data))
print('</--->')
except FileNotFoundError as e:
print(f'Error: {e}')
@@ -119,8 +131,6 @@ def main():
generator = html_generator.HtmlTemplate(args.template)
template = generator.prepare_template(invoice_data, envelope_data)
print(template)
try:
print('Generating invoice...')
invoice_pdf = Path(invoice_data.Id).with_suffix('.pdf')

View File

@@ -15,7 +15,6 @@ Positions:
- Title: "Aschkriechen"
SubTitle: "Leistungszeitraum: 10/2022"
PricePerUnit: 77.88
Quantity: 3

View File

@@ -112,6 +112,10 @@
border-top: .1pt solid black;
}
.center {
text-align: center;
}
.head_data {
width: 100%;
border-collapse: collapse;
@@ -136,7 +140,7 @@
<body>
<!-- Content for Static Frame 'header_frame' -->
<div id="address_frame_content">
<p class="underline">{{ envelope.AddressContent.AddressBoxSender }}</p>
<p class="underline small center">{{ envelope.AddressContent.AddressBoxSender }}</p>
<address>
{{ invoice.AddressField | markdown_to_html }}
</address>
@@ -188,20 +192,17 @@
{% endfor %}
<tr class="summe">
<td></td>
<td></td>
<td class="rechts">Nettosumme:</td>
<td colspan="2" class="rechts">Nettosumme:</td>
<td class="rechts">{{ format_float(calculate_total(invoice)) }}</td>
</tr>
<tr>
<td></td>
<td></td>
<td class="rechts">USt. ({{ format_float(invoice.Vat) }}%):</td>
<td colspan="2" class="rechts">USt. ({{ format_float(invoice.Vat) }}%):</td>
<td class="rechts">{{ format_float(calculate_total(invoice) * ((invoice.Vat / 100))) }}</td>
</tr>
<tr>
<td></td>
<td></td>
<td class="rechts bold overline">Gesamt Summe:</td>
<td colspan="2" class="rechts bold overline">Gesamt Summe:</td>
<td class="rechts bold overline">{{ format_float(calculate_total(invoice) * ((invoice.Vat / 100)+1)) }}</td>
</tr>
</table>