Commit Graph
135 Commits
Author SHA1 Message Date
David Malinowski bcafb78fa7 fix(msp): Gutschriften nicht gegen reguläre Rechnungen deduplizieren + Title nach Insert setzen
Zwei Bugs beim ersten realen Gutschrift-Test (ADN-CSV vom 16.10.2025, 2 Zeilen
mit negativer Menge):

1. Dedup-Fehler — Gutschriftzeilen wurden als „bereits importiert" geskippt,
   weil die Prüfung (subscription_external_id, period_start, period_end) auch
   bei der regulären Rechnung desselben Monats matchte. Gutschriften sind aber
   inhaltlich Korrekturen, keine Dubletten. Fix: Dedup greift nur bei
   regulären Rechnungszeilen, nicht bei Gutschriftzeilen (qty<0, amount<0
   oder document_type=Gutschrift).

2. Title-Override — ERPNext setzt bei Sales-Invoice-Insert den Title aus der
   autoname-Schablone auf ``{customer_name}``, wodurch unser „Abrechnung
   Microsoft Abo MM.JJJJ" verloren ging. Fix: nach doc.insert() den Title
   direkt per db.set_value wieder einsetzen (umgeht Auto-Title-Logik).

Ergebnis der Validierung (Oktober 2025, das einzige Monat mit Gutschrift-
Zeilen in den verfügbaren CSVs):
- SINV-271450: CUST-21844, -2× MAPID-20763063, Netto -11,76 / Brutto -13,99
- SINV-271455: CUST-21865, -5× ITEM-00052, Netto -123,60 / Brutto -147,08
- Beide mit is_return=1 und korrektem Titel „Gutschrift Microsoft Abo 10.2025"

Nebenbefund zu adnconnect: historische Gutschriftbehandlung dort fehlerhaft —
die -2-Zeile von CUST-21844 landete in der Haupt-SI mit Rabatt=100 %
(Gutschrift-Effekt verloren), die -5-Zeile von CUST-21865 wurde komplett
verschluckt. Unser Importer deckt das jetzt sauber ab.
2026-04-14 17:32:57 +02:00
David Malinowski d165190b87 fix(msp): Steuer-Template-Zeilen explizit kopieren, nicht nur referenzieren
Bisher hat der Builder nur ``doc.taxes_and_charges = template_name`` gesetzt und
darauf vertraut, dass Frappe die Steuerzeilen aus dem Template auto-populiert.
Das Verhalten war aber nicht zuverlässig: in vielen Fällen entstand eine
taxes-Zeile mit ``rate=0``, wodurch Items ohne eigenes item_tax_template
komplett aus der Steuerberechnung fielen (z. B. Power BI Pro bei CUST-21116:
174,44 € netto ohne MwSt. → 33,14 € fehlende Steuer).

adnconnect löst das mit explizitem Kopieren der Template-Zeilen in die
taxes-Tabelle des SI. Wir spiegeln das Verhalten in
``DocumentBuilder._copy_tax_template_rows`` und rufen es sowohl für Sales
Invoices als auch Delivery Notes auf.

Ergebnis der Validierung:
- 226 / 226 Vergleichsfälle in den Monaten 11.2025–02.2026 sind jetzt
  bit-genau deckungsgleich mit adnconnect (vorher 218 / 226).
- Keine verbleibenden Stammdaten-Drift-Differenzen mehr.
2026-04-14 16:52:02 +02:00
David Malinowski f284399fec feat(msp): License Coverage — lieferantenneutrale Inklusiv-Lizenzen mit Builder-Integration
Generalisierung des bisher nur in adnconnect existierenden Konzepts „inkludierte
Lizenzen" (über IT-Verträge gedeckte Microsoft-Seats) in einen lieferantenneutralen
DocType im MSP-Modul. Damit wird die Pauschal-Vertrags-Logik unabhängig vom
Distributor (ADN heute, ALSO/Ingram/Pax8 morgen).

Datenmodell:
- License Coverage (parent): customer + optional it_contract / valid_from /
  valid_to + enabled-Toggle + freie Notes. Mehrere Coverages pro Kunde sind
  zulässig (z. B. mehrere Standorte, parallele Verträge).
- License Coverage Item (child): item-Link (lieferantenagnostisch) + qty.
  vendor_product_id wird vom Item gefetched für Plausibilität / Dokumentation.

Builder-Integration (msp.importers.coverage + builder.py):
- Pro Importlauf wird ein CoverageCache aller relevanten Kunden einmal aus der
  DB geladen (eine SQL-Abfrage statt N pro Position).
- _append_line splittet jede CanonicalRow bei Bedarf in zwei Sales-Invoice-/
  Delivery-Note-Items: min(qty, covered) mit discount_percentage=100 +
  „ohne Berechnung"-Hinweis, plus Restmenge zum Listpreis.
- Subscription-Event referenziert die primäre (=erste) Item-Row, das
  supply_subscription-Link wird auf allen Item-Rows der kanonischen Zeile
  gesetzt.
- Coverage greift nur bei echten Rechnungen, nicht bei Gutschriften.

Migration:
- Patch migrate_adn_included_services_to_license_coverage übernimmt bestehende
  ADN Included Services (parent + items) idempotent in License Coverage. Marker
  im Notes-Feld verhindert Doppel-Migration. Auf dem Testsystem 5/5 Records
  korrekt portiert.

Validation:
- Re-Import der 5 Test-Monate (Nov 2025 – Mär 2026) zeigt: die 5 Coverage-Kunden
  produzieren jetzt deckungsgleiche Beträge zu adnconnect (z. B. CUST-21877:
  10× Premium berechnet + 11× zum 100%-Rabatt = exakt das Muster von
  SINV-269822). Verbleibende Diffs nur noch durch Power-BI-Pro-Tax-Template
  auf Testsystem.

Reconciliation-POC erweitert: erp_coverage() liest die License Coverage über
die ERPNext-REST-API; Reconciliation-Tabelle zeigt jetzt Spalten Graph / ERP /
Coverage / Billable mit klassifizierten Status-Hinweisen (z. B. „Coverage > Graph
= Upsell-Chance").
2026-04-14 14:03:56 +02:00
David Malinowski 0fa8c70655 fix(msp): Kundenrechnung mit Listpreis, Einkaufspreis + Marge separat
Wichtige Semantik-Korrektur: Der Distributor-Rabatt in ADN-CSVs (z. B.
17,5 %) ist die Wiederverkäufer-Marge von itsdave und darf NICHT an den
Endkunden durchgereicht werden. Der Kunde zahlt den LISTPREIS; itsdave
bezahlt an ADN den EINZELPREIS (= Listpreis × (1 − Rabatt)).

Bisher hat der Builder fälschlich den Einzelpreis als Sales-Invoice-Rate
verwendet — der Kunde hätte dadurch rund 17,5 % zu wenig berechnet
bekommen.

Änderungen:
- builder.py: rate = row.list_price (Fallback: unit_price, amount/qty)
- subscriptions.py: Supply Subscription Event trägt jetzt sowohl
  Kundensicht (rate, amount) als auch Einkaufssicht (cost_rate,
  cost_amount, reseller_discount_pct).
- supply_subscription_event: neue Sektion „Einkauf & Marge" mit
  cost_rate, cost_amount, reseller_discount_pct, margin_amount
  (automatisch berechnet: amount − cost_amount).

Diff-Test Feb-2026-CSV:
50 von 57 Kunden nun deckungsgleich mit adnconnect.
7 verbleibende Diffs:
  5 echte adnconnect-Bugs (Split-Logik / leere SIs) — in Summe 762 €
    Unterabrechnung gegenüber korrektem Listpreis
  2 Testsystem-Tax-Template-Drift (Power BI Pro) — kein Code-Problem
2026-04-14 12:56:42 +02:00
David Malinowski 1a92d4c545 feat(msp): MSP-Workspace um Lieferanten-Import-Sektion erweitert
Fügt dem MSP-Workspace einen neuen Card-Break „Lieferanten-Import" hinzu
mit Links zu Supplier Import Run, Supplier Import Profile, Supply
Subscription und Supply Subscription Event. Zusätzlich neue Shortcuts
für Lieferanten-Import und Supply Subscriptions.

Damit ist der neue Importer über das reguläre MSP-Desk-Menü erreichbar;
die alte adnconnect-App hat keinen eigenen Workspace-Eintrag und bleibt
weiterhin für Historie-Zugriff installiert, aber nicht mehr als
primärer Einstiegspunkt sichtbar.
2026-04-14 12:43:50 +02:00
David Malinowski be54b61b56 feat(msp): ADN-Supplier-Import-Profile als Fixture + hooks.py Export
Checkt ein vollständiges Profil „ADN Monthly CSV v1" als Fixture ein und
erweitert die fixtures-Konfiguration in hooks.py, damit der Record bei
Bench-Install/-Update idempotent angelegt wird. Damit ist der ADN-Import
nach Installation der MSP-App sofort einsatzbereit, ohne dass das Profil
manuell konfiguriert werden muss.

Die Defaults entsprechen der bisherigen adnconnect-Konfiguration
(itsdave GmbH, MwSt. 19 %, Standard-AGBs, Titelpräfix „Abrechnung
Microsoft Abo ").
2026-04-14 12:41:58 +02:00
David Malinowski 384378b605 chore(msp): Dev-/Test-Helfer für Supplier-Import (nur Entwicklungs-Hilfsmittel)
Nicht-produktive Helper-Module im importers/-Paket, mit Unterstrich-Präfix
markiert. Werden von keiner Produktiv-Codebasis aufgerufen, sondern nur
manuell über `bench execute`:

- _smoke_test: parst eine CSV und gibt Verteilungsstatistiken aus
  (distinct customers/products, enums).
- _runner: Convenience-Wrapper, um einen bestehenden Import-Run per
  Namen zu starten.
- _inspect: liefert kompakte JSON-Übersicht über einen Import-Run
  (Status, Statistik, erste Zeilen) zur Fehlersuche.
- _batchtest: importiert mehrere CSVs chronologisch und summiert
  Subscription-/Event-Zahlen.
- _cleanup: löscht alles, was vom neuen Importer erzeugt wurde. Nur für
  Dev-/Test-Instanzen gedacht; prüft vorab auf test-DB oder
  developer_mode.
2026-04-14 12:41:48 +02:00
David Malinowski 687a1faac0 feat(msp): Parser-Framework + DocumentBuilder + Run-Orchestrator
Implementiert das eigentliche Import-Framework im Paket msp.importers/:

- base.py: abstrakte BaseSupplierParser-Klasse + CanonicalRow-Dataclass
  (lieferantenneutrale Repräsentation einer Rechnungsposition) sowie
  Helfer für deutsche Dezimal-/Datums-Parser und Enum-Normalisierung
  (Monthly/Annual/Triennial, P1M/P1Y/P3Y, New/Renewal/Billing/Upgrade/
  Cancel).
- registry.py: Parser-Registry, über parser_key aufgelöst. Neue
  Lieferanten bringen einen eigenen Parser mit und registrieren sich
  per @register-Dekorator.
- adn_monthly_csv.py: Parser für ADNs monatliche Rechnungs-CSV.
  Extrahiert alle relevanten Felder strukturiert, inklusive
  SUBSCRIPTION_ID_EXTERNAL, BILLINGPLAN, VERTRAGSDAUER, WARTUNGSBEGINN/
  -ENDE und BUCHUNGSTYP — Daten, die der alte adnconnect-Importer
  verworfen oder nur in HTML-Descriptions vergraben hatte.
- resolution.py: Lookups für Customer + Item und die Output-Mode-
  Selektion (Run-Override → Customer.billing_mode → Profil-Default).
- subscriptions.py: Upsert-Logik für Supply Subscription + Event,
  inklusive Deduplizierung per (subscription_external_id, period).
- builder.py: DocumentBuilder, der sowohl Sales Invoices als auch
  Delivery Notes aus kanonischen Zeilen erzeugt. Rechnungspreise werden
  per unit_price × qty gesetzt (mit Rabatt in description) — korrekt
  gemäß ADN-POSITIONSPREIS statt adnconnects fehlerhafter Listenpreis/
  discount_percentage-Kombination.
- run_orchestrator.py: verdrahtet das Ganze und wird aus dem
  Supplier-Import-Run-Controller über die Whitelisted-Methode do_import
  aufgerufen.
2026-04-14 12:41:37 +02:00
David Malinowski b399b6f37d feat(msp): Supply Subscription data model + Supplier Import scaffolding
Führt ein lieferantenagnostisches Lizenzmodell ein, das den Weg für den
künftigen Ersatz der adnconnect-App ebnet:

- Supply Subscription: Golden Record pro Subscription-Lifecycle, unique
  über die externe Vendor-Subscription-ID (z. B. Microsoft Subscription-ID).
  Denormalisierte Felder current_period_end, qty_current, last_event_date
  werden aus den Events gepflegt.
- Supply Subscription Event: Eine Episode pro Abrechnungszeitraum, mit
  Rück-Links auf Sales Invoice, Delivery Note, Purchase Invoice und
  Supplier Import Line.
- Supplier Import Profile / Run / Line: Modulares Import-Framework, in dem
  pro Lieferant (ADN, künftig ALSO/Ingram/…) ein Profil mit parser_key +
  Defaults konfigurierbar ist. Ein Run bündelt einen konkreten Import
  inklusive Kanonik-Zeilen und Statistiken.
- Custom Field „supply_subscription" auf Sales Invoice Item und Delivery
  Note Item — das ist das einzige Standard-ERPNext-Feld, das unabhängig
  vom Lieferanten hinzukommt. Alle weiteren Attribute werden über den
  Link erreichbar.

Die Importer-Logik liegt separat (nächster Commit).
2026-04-14 12:41:14 +02:00
David MalinowskiandClaude Opus 4.6 b014ed596b feat: add Git fields on IT Object, Contact custom fields, translations
- IT Object: git_remote_url, git_branch, git_path_on_host (visible
  only when type = Git Repository)
- Contact custom fields: teams_user_id, is_external_contractor,
  contractor_for (via fixtures)
- Remove x509_certificate hooks from hooks.py (moved to DocType controller)
- Add Custom Field fixture export filter to hooks.py
- German translations (de.csv) for all new DocTypes and fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:05:58 +02:00
David MalinowskiandClaude Opus 4.6 382be5fa33 feat: add Worklog Mapping DocType
- Maps work tracker projects, local directories, chat participants
  to customers for automated work time attribution
- Fields: customer, source_type, pattern (glob), employee, note

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:05:58 +02:00
David MalinowskiandClaude Opus 4.6 549963affd feat: replace x509_certificate with SSL Certificate DocType
- Rename x509_certificate → SSL Certificate (DocType, table, files)
- Rename child tables to SSL Certificate Domain/Installation
- ZIP import: extracts .crt.pem, .key.pem, .ca.pem, .csr.pem
- Auto-parse: CN, issuer, SANs, validity, wildcard, cert type
- Private key stored encrypted (Password field)
- Download buttons: cert, key, fullchain, cert+key, CA, CSR
- Copy-to-clipboard with HTTP fallback
- Certificate details as HTML table
- Key verification (signature check) and CA chain validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:05:58 +02:00
David MalinowskiandClaude Opus 4.6 7f5f7a5236 feat: add IT Domain DocType with import wizard and enrichment
- New DocType IT Domain for centralized domain management
- Hetzner CSV import (domains + handles with registrant data)
- DomainReselling.de API import (live domain + contact fetch)
- DNS/HTTP/SSL enrichment (IP, MX, website title, SSL info)
- Customer suggestion engine (handle, registrant, title, domain matching)
- Interactive assignment dialog with bulk-assign
- Colored badges for DNS hosting and MX routing in list view
- German translations

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:05:58 +02:00
David MalinowskiandClaude Opus 4.6 4bf40ff70a fix: apply_ohne_berechnung sets values directly to avoid async recalculation conflicts
frappe.model.set_value in a loop triggered ERPNext pricing recalculation per item,
causing values to be overwritten. Now sets values on locals objects directly and
triggers a single recalculation at the end.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 14:07:40 +01:00
Dave 1fca135a83 chore: commit uncommitted production changes for v16 migration 2026-03-07 09:47:25 +01:00
Dave 208212a883 fixes, trmm, win11 2025-11-15 23:34:07 +01:00
Beate Trenziok 0fb8d8a479 Anpassungen AutuInvoiceGenerator, SO Billed Script 2025-10-15 12:46:05 +02:00
Beate Trenziok 1d7bb628d1 Anpassung 2025-04-01 10:07:00 +02:00
Beate Trenziok 3201c6fa8f Merge branch 'main' of https://github.com/itsdave-de/msp 2025-04-01 10:06:00 +02:00
Beate Trenziok c74531fcbc Rechnung nach SR Arbeitszeit sortieren 2025-04-01 09:48:18 +02:00
Dave ddf8a837fb merge 2025-03-13 23:54:50 +01:00
Dave e83d61d8a4 docuemtation improvements 2025-03-13 23:48:22 +01:00
Beate Trenziok 5830529ca8 Anpassungen detailierte Items, Bug Tagesumbruch 2025-03-07 10:51:02 +01:00
Beate Trenziok 3b4e0dd755 Anpassung Surcharge 2024-10-04 12:42:52 +02:00
Beate Trenziok 0bafeac13f Anpassung Password und Permissions 2024-08-13 09:18:43 +02:00
Beate Trenziok 936040fcb1 Anpassung scheduler 2024-08-12 10:42:43 +02:00
Beate Trenziok 8679e44386 Anpassung Status 0 2024-08-09 11:44:25 +02:00
Beate Trenziok 0803d09d78 Anpassungen Offork 2024-08-08 14:39:26 +02:00
Beate Trenziok 1c739076bc Anpassung ASAP Modus 2024-08-02 11:57:49 +02:00
Beate Trenziok f88d9bc7d4 merge 2024-08-01 06:47:27 +02:00
Beate Trenziok 7d7ed25709 fetch also work from tickets, for performance stats 2024-08-01 06:26:06 +02:00
Beate Trenziok ca64ff2e62 fixes for customer_quick_entry in v15 2024-08-01 06:23:49 +02:00
Beate Trenziok 1909ff6ed9 Auto invoice generator: Allow creation of invoices, though we have drafts for a customer, skip positions from drafts. 2024-08-01 06:23:19 +02:00
Dave 70f8dc9a84 Dashboard Technik with Perfomance Chart 2024-07-31 17:43:54 +02:00
Dave 6660093ccb comment out some prints for getting overview 2024-07-31 17:43:22 +02:00
Dave 4ab3b5f7d6 changes for employee_target_agreement 2024-07-31 17:41:02 +02:00
Dave 8e691469ba fix jinja methods for item label for v14 2024-07-02 10:09:11 +02:00
Beate Trenziok 4653083a5d Anpassung freeze, und datetime 2024-06-28 10:53:21 +02:00
Beate Trenziok 124fa2f3e3 Anpassung Styler V15 2024-06-27 09:29:46 +02:00
Your Name d3b3551681 Merge branch 'main' of https://github.com/itsdave-de/msp 2024-06-14 12:26:41 +02:00
Your Name e3327adaf9 certificate management 2024-06-14 12:22:58 +02:00
Your Name 10d71f747f certificate management 2024-06-07 12:33:26 +02:00
Luiz Costa 89858135f8 add pandas python requirements 2024-05-31 10:53:56 +01:00
Beate Trzensiok 1d8860ec8c Employee Target Agreement 2024-02-20 10:15:40 +01:00
Beate Trzensiok a0a6759c65 Merge branch 'main' of https://github.com/itsdave-de/msp into main 2024-02-20 10:13:47 +01:00
Beate Trzensiok 896d8db5b9 Item get act Stock 2024-02-14 10:30:37 +01:00
Dave b4d2509629 Method for copying Attachments from one doctype to another 2023-08-17 13:14:58 +02:00
Dave a985f8524c repair Location 2023-06-13 16:41:27 +02:00
Dave b141c968ea MSP Documentation chagnes and Print format 2023-06-09 08:29:48 +02:00
Dave 65386bae8e Merge branch 'main' of https://github.com/itsdave-de/msp 2023-06-09 07:03:57 +02:00