Compare commits
2 Commits
0bbaa78d0e
...
b8bd3f288b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8bd3f288b | ||
|
|
6f1120c8b4 |
10
.idea/freelance_invoice.iml
generated
10
.idea/freelance_invoice.iml
generated
@@ -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>
|
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
6
.idea/inspectionProfiles/profiles_settings.xml
generated
@@ -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
7
.idea/misc.xml
generated
@@ -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
8
.idea/modules.xml
generated
@@ -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
6
.idea/vcs.xml
generated
@@ -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
132
.idea/workspace.xml
generated
@@ -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>
|
|
||||||
@@ -32,8 +32,7 @@ class HtmlTemplate:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def calculate_total(invoice_data):
|
def calculate_total(invoice_data):
|
||||||
return sum(
|
return sum((pos['Quantity'] * pos['PricePerUnit']) for pos in invoice_data.Positions)
|
||||||
(pos['Quantity'] * (pos['PricePerUnit'] or invoice_data.PricePerUnit)) for pos in invoice_data.Positions)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def named_replace(value, **replacements):
|
def named_replace(value, **replacements):
|
||||||
|
|||||||
20
src/main.py
20
src/main.py
@@ -86,13 +86,16 @@ def main():
|
|||||||
|
|
||||||
print('Envelope data:')
|
print('Envelope data:')
|
||||||
envelope_data = DataObject(**envelope)
|
envelope_data = DataObject(**envelope)
|
||||||
print(envelope_data.__dict__)
|
print('<--->')
|
||||||
|
print(yaml.dump(envelope_data))
|
||||||
|
print('</--->')
|
||||||
|
|
||||||
print('Invoice data:')
|
print('Invoice data:')
|
||||||
invoice_data = DataObject(**invoice)
|
invoice_data = DataObject(**invoice)
|
||||||
merge_envelope_data_into_invoice_data(invoice_data, envelope_data.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)
|
merge_envelope_data_into_invoice_data(invoice_data, selected_customer)
|
||||||
|
|
||||||
if not hasattr(invoice_data, 'InvoiceDate'):
|
if not hasattr(invoice_data, 'InvoiceDate'):
|
||||||
@@ -103,8 +106,17 @@ def main():
|
|||||||
if not hasattr(invoice_data, 'Id'):
|
if not hasattr(invoice_data, 'Id'):
|
||||||
invoice_data.Id = None
|
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
|
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:
|
except FileNotFoundError as e:
|
||||||
print(f'Error: {e}')
|
print(f'Error: {e}')
|
||||||
@@ -119,8 +131,6 @@ def main():
|
|||||||
generator = html_generator.HtmlTemplate(args.template)
|
generator = html_generator.HtmlTemplate(args.template)
|
||||||
template = generator.prepare_template(invoice_data, envelope_data)
|
template = generator.prepare_template(invoice_data, envelope_data)
|
||||||
|
|
||||||
print(template)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print('Generating invoice...')
|
print('Generating invoice...')
|
||||||
invoice_pdf = Path(invoice_data.Id).with_suffix('.pdf')
|
invoice_pdf = Path(invoice_data.Id).with_suffix('.pdf')
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ Positions:
|
|||||||
|
|
||||||
- Title: "Aschkriechen"
|
- Title: "Aschkriechen"
|
||||||
SubTitle: "Leistungszeitraum: 10/2022"
|
SubTitle: "Leistungszeitraum: 10/2022"
|
||||||
PricePerUnit: 77.88
|
|
||||||
Quantity: 3
|
Quantity: 3
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,10 @@
|
|||||||
border-top: .1pt solid black;
|
border-top: .1pt solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.head_data {
|
.head_data {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
@@ -136,7 +140,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<!-- Content for Static Frame 'header_frame' -->
|
<!-- Content for Static Frame 'header_frame' -->
|
||||||
<div id="address_frame_content">
|
<div id="address_frame_content">
|
||||||
<p class="underline">{{ envelope.AddressContent.AddressBoxSender }}</p>
|
<p class="underline small center">{{ envelope.AddressContent.AddressBoxSender }}</p>
|
||||||
<address>
|
<address>
|
||||||
{{ invoice.AddressField | markdown_to_html }}
|
{{ invoice.AddressField | markdown_to_html }}
|
||||||
</address>
|
</address>
|
||||||
@@ -188,20 +192,17 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
<tr class="summe">
|
<tr class="summe">
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td colspan="2" class="rechts">Nettosumme:</td>
|
||||||
<td class="rechts">Nettosumme:</td>
|
|
||||||
<td class="rechts">{{ format_float(calculate_total(invoice)) }}</td>
|
<td class="rechts">{{ format_float(calculate_total(invoice)) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td colspan="2" class="rechts">USt. ({{ format_float(invoice.Vat) }}%):</td>
|
||||||
<td class="rechts">USt. ({{ format_float(invoice.Vat) }}%):</td>
|
|
||||||
<td class="rechts">{{ format_float(calculate_total(invoice) * ((invoice.Vat / 100))) }}</td>
|
<td class="rechts">{{ format_float(calculate_total(invoice) * ((invoice.Vat / 100))) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td colspan="2" class="rechts bold overline">Gesamt Summe:</td>
|
||||||
<td class="rechts bold overline">Gesamt Summe:</td>
|
|
||||||
<td class="rechts bold overline">{{ format_float(calculate_total(invoice) * ((invoice.Vat / 100)+1)) }}</td>
|
<td class="rechts bold overline">{{ format_float(calculate_total(invoice) * ((invoice.Vat / 100)+1)) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
Reference in New Issue
Block a user