This commit is contained in:
oliver committed 2026-10-12 10:09:44 -03:00
1 parent 1ea3de74f2
commit 9db080faea
8 files changed
+2064 -55

No files matched your search

+428
View File
@@ -0,0 +1,428 @@
-- =============================================================================
-- Quartal Schweiz – Gesamt (ODOO + AMAZON), Lieferung in die Schweiz
-- Odoo 17 / PostgreSQL
--
-- Zweck:
-- Dieselben Spalten wie Alle_Rechnungen.sql (inkl. "Quelle"), aber:
-- * Zeitraum = QUARTAL statt Monat
-- * nur Rechnungen mit Lieferung in die SCHWEIZ (Lieferland = 'CH')
--
-- Modelle:
-- ODOO : account.move (Kundenrechnungen / Gutschriften)
-- AMAZON : brandize_datacenter_amazon_vat_transaction
--
-- Parameter:
-- %(quarter)s Quartal als Text, z. B. '2026-Q3'
-- ODOO : Rechnungsdatum im Quartal (siehe quarters-CTE)
-- AMAZON: activity_period in den 3 Monaten des Quartals
--
-- Aufruf (Odoo / psycopg2):
-- cr.execute(open('Quartal_Schweiz.sql').read(), {'quarter': '2026-Q3'})
--
-- In psql stattdessen:
-- \set quarter '2026-Q3'
--
-- ---------------------------------------------------------------------------
-- Spalten-Mapping ODOO -> AMAZON
-- (Felder ohne Amazon-Pendant bleiben leer)
-- ---------------------------------------------------------------------------
-- Rechnungsdatum <- transaction_complete_date (Fallback: depart)
-- Rechnungsnummer <- vat_inv_number
-- Rechnungsland <- Name zu sale_arrival_country (res_country)
-- Rechnungsland Code <- sale_arrival_country
-- Zahlart <- '' (kein Amazon-Feld)
-- Zahlungsreference <- transaction_event_id
-- USt. Id Kaeufer <- buyer_vat_number
-- Gesamtpreis brutto <- total_activity_value_amt_vat_incl
-- Gesamtpreis netto <- total_activity_value_amt_vat_excl
-- Brutto / -erm <- Steuersplit nach effektivem Satz (Schwelle
-- USt. Satz / -erm CH >= 8, sonst >= 16 - wie im ODOO-Export)
-- Netto Betrag / -erm Satz = total_activity_value_vat_amt / netto * 100
-- Versandkosten brutto <- total_ship_charge_amt_vat_incl
-- Versandkosten netto <- total_ship_charge_amt_vat_excl
-- Auftragsdatum <- transaction_depart_date
-- Bestellnummer <- activity_transaction_id
-- Zahldatum <- '' (kein Amazon-Feld)
-- Lieferadresse Name <- buyer_name
-- Tag <- '' (kein Amazon-Feld)
-- Lieferland <- Name zu arrival_country (res_country)
--
-- ACHTUNG: Das Amazon-Mapping ist eine 1:1-Uebertragung auf die ODOO-Spalten.
-- Die Datumszuordnung (Rechnungsdatum/Auftragsdatum) sowie Bestellnummer
-- sollten gegen die tatsaechliche Amazon-Report-Semantik geprueft und hier
-- ggf. angepasst werden.
-- =============================================================================
WITH params AS (
-- Quartal aus %(quarter)s (z. B. '2026-Q3') ableiten.
SELECT
split_part(%(quarter)s, '-', 1) AS yr,
right(split_part(%(quarter)s, '-', 2), 1)::int AS qn
),
quarters AS (
SELECT
yr,
qn,
make_date(yr::int, (qn - 1) * 3 + 1, 1) AS first_day,
make_date(yr::int, (qn - 1) * 3 + 1, 1) + INTERVAL '3 months' AS next_day
FROM params
),
-- Die drei activity_period-Werte (Format 'YYYY-MMM', deutsche Kuerzel) fuer die
-- Amazon-Tabelle.
qmonths AS (
SELECT
q.yr || '-' || CASE ((q.qn - 1) * 3 + m.m)
WHEN 1 THEN 'JAN' WHEN 2 THEN 'FEB' WHEN 3 THEN 'MÄR'
WHEN 4 THEN 'APR' WHEN 5 THEN 'MAI' WHEN 6 THEN 'JUN'
WHEN 7 THEN 'JUL' WHEN 8 THEN 'AUG' WHEN 9 THEN 'SEP'
WHEN 10 THEN 'OKT' WHEN 11 THEN 'NOV' WHEN 12 THEN 'DEZ'
END AS activity_period
FROM quarters q
CROSS JOIN generate_series(1, 3) AS m(m)
),
-- ===========================================================================
-- ODOO-Seite (identisch zu Rechnungsexport.sql)
-- ===========================================================================
invoices AS (
SELECT
am.id,
am.name,
am.ref,
am.move_type,
am.invoice_date,
am.invoice_origin,
am.partner_id,
am.partner_shipping_id,
am.invoice_payment_term_id,
am.payment_reference
FROM account_move am
CROSS JOIN quarters q
WHERE am.invoice_date >= q.first_day
AND am.invoice_date < q.next_day
AND am.move_type IN ('out_invoice', 'out_refund')
),
line_taxes AS (
SELECT
aml.move_id AS invoice_id,
at.amount AS tax_rate,
SUM(aml.price_subtotal) AS netto,
SUM(aml.price_total) AS brutto
FROM invoices inv
JOIN account_move_line aml
ON aml.move_id = inv.id
JOIN account_move_line_account_tax_rel amlatr
ON amlatr.account_move_line_id = aml.id
JOIN account_tax at
ON at.id = amlatr.account_tax_id
GROUP BY aml.move_id, at.amount
),
tax_split AS (
SELECT
lt.invoice_id,
MAX(CASE
WHEN (rc.code = 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 8)
OR (COALESCE(rc.code, '') <> 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 16)
THEN ROUND(lt.brutto::numeric, 2)
END) AS brutto_normal,
MAX(CASE
WHEN (rc.code = 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 8)
OR (COALESCE(rc.code, '') <> 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 16)
THEN ROUND(lt.tax_rate::numeric, 2)
END) AS ust_satz_normal,
MAX(CASE
WHEN (rc.code = 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 8)
OR (COALESCE(rc.code, '') <> 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 16)
THEN ROUND(lt.netto::numeric, 2)
END) AS netto_normal,
MAX(CASE
WHEN NOT (
(rc.code = 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 8)
OR (COALESCE(rc.code, '') <> 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 16)
)
THEN ROUND(lt.brutto::numeric, 2)
END) AS brutto_erm,
MAX(CASE
WHEN NOT (
(rc.code = 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 8)
OR (COALESCE(rc.code, '') <> 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 16)
)
THEN ROUND(lt.tax_rate::numeric, 2)
END) AS ust_satz_erm,
MAX(CASE
WHEN NOT (
(rc.code = 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 8)
OR (COALESCE(rc.code, '') <> 'CH' AND ROUND(lt.tax_rate::numeric, 2) >= 16)
)
THEN ROUND(lt.netto::numeric, 2)
END) AS netto_erm
FROM line_taxes lt
JOIN invoices inv
ON inv.id = lt.invoice_id
JOIN res_partner rp
ON rp.id = inv.partner_id
LEFT JOIN res_country rc
ON rc.id = rp.country_id
GROUP BY lt.invoice_id
),
shipping AS (
SELECT
aml.move_id AS invoice_id,
ROUND(SUM(aml.price_total)::numeric, 2) AS shipping_brutto,
ROUND(SUM(aml.price_subtotal)::numeric, 2) AS shipping_netto
FROM invoices inv
JOIN account_move_line aml
ON aml.move_id = inv.id
JOIN product_product pp
ON pp.id = aml.product_id
JOIN product_template pt
ON pt.id = pp.product_tmpl_id
WHERE pt.categ_id = 9
GROUP BY aml.move_id
),
invoice_tags AS (
SELECT
inv.id AS invoice_id,
STRING_AGG(
DISTINCT COALESCE(ct.name->>'en_US', ct.name->>'de_DE', ''),
', ' ORDER BY COALESCE(ct.name->>'en_US', ct.name->>'de_DE', '')
) AS tags
FROM invoices inv
JOIN sale_order so
ON so.name = inv.invoice_origin
JOIN sale_order_tag_rel sotr
ON sotr.order_id = so.id
JOIN crm_tag ct
ON ct.id = sotr.tag_id
GROUP BY inv.id
),
invoice_transaction_reference AS (
SELECT
rel.invoice_id,
pt.provider_reference,
ROW_NUMBER() OVER (
PARTITION BY rel.invoice_id
ORDER BY pt.id
) AS rn
FROM account_invoice_transaction_rel rel
JOIN payment_transaction pt
ON pt.id = rel.transaction_id
),
sale_info AS (
SELECT
inv.id AS invoice_id,
MIN(so.date_order) AS order_date
FROM invoices inv
JOIN sale_order so
ON so.name = inv.invoice_origin
GROUP BY inv.id
),
invoice_payments AS (
SELECT
aml.move_id AS invoice_id,
MAX(apr.max_date) AS payment_date
FROM invoices inv
JOIN account_move_line aml
ON aml.move_id = inv.id
JOIN account_account aa
ON aa.id = aml.account_id
AND aa.account_type = 'asset_receivable'
JOIN account_partial_reconcile apr
ON apr.debit_move_id = aml.id
OR apr.credit_move_id = aml.id
GROUP BY aml.move_id
),
odoo_rows AS (
SELECT
TO_CHAR(inv.invoice_date, 'YYYY-MM-DD') AS "Rechnungsdatum",
CASE
WHEN inv.move_type = 'out_refund'
THEN COALESCE(inv.name, inv.ref, '') || '-gs'
ELSE COALESCE(inv.name, inv.ref, '')
END AS "Rechnungsnummer",
COALESCE(rc_inv.name->>'en_US', rc_inv.name->>'de_DE', '') AS "Rechnungsland",
COALESCE(rc_inv.code, '') AS "Rechnungsland Ländercode",
COALESCE(apt.name->>'en_US', apt.name->>'de_DE', '') AS "Zahlart",
COALESCE(itr.provider_reference, '') AS "Zahlungsreference der Bestellung",
COALESCE(partner.vat, '') AS "USt. Id / VAT Id des Käufers (in Bestellung)",
ROUND(COALESCE(ts.brutto_normal, 0) + COALESCE(ts.brutto_erm, 0), 2) AS "Gesamtpreis brutto",
ROUND(COALESCE(ts.netto_normal, 0) + COALESCE(ts.netto_erm, 0), 2) AS "Gesamtpreis netto",
COALESCE(ts.brutto_normal, 0) AS "Brutto",
COALESCE(ts.brutto_erm, 0) AS "Brutto erm",
COALESCE(ts.ust_satz_normal, 0) AS "USt. Satz",
COALESCE(ts.ust_satz_erm, 0) AS "Ust. Satz erm",
COALESCE(ts.netto_normal, 0) AS "Netto Betrag",
COALESCE(ts.netto_erm, 0) AS "Netto Betrag erm",
COALESCE(sh.shipping_brutto, 0) AS "Versandkosten brutto",
COALESCE(sh.shipping_netto, 0) AS "Versandkosten netto",
COALESCE(TO_CHAR(si.order_date, 'YYYY-MM-DD'), '') AS "Auftragsdatum",
COALESCE(inv.invoice_origin, '') AS "Bestellnummer",
COALESCE(TO_CHAR(ip.payment_date, 'YYYY-MM-DD'), '') AS "Zahldatum",
COALESCE(ship.name, partner.name, '') AS "Lieferadresse Name",
COALESCE(it.tags, '') AS "Tag",
COALESCE(
rc_ship.name->>'en_US', rc_ship.name->>'de_DE',
rc_inv.name->>'en_US', rc_inv.name->>'de_DE',
''
) AS "Lieferland"
FROM invoices inv
JOIN res_partner partner
ON partner.id = inv.partner_id
LEFT JOIN res_country rc_inv
ON rc_inv.id = partner.country_id
LEFT JOIN res_partner ship
ON ship.id = inv.partner_shipping_id
LEFT JOIN res_country rc_ship
ON rc_ship.id = ship.country_id
LEFT JOIN account_payment_term apt
ON apt.id = inv.invoice_payment_term_id
LEFT JOIN tax_split ts
ON ts.invoice_id = inv.id
LEFT JOIN shipping sh
ON sh.invoice_id = inv.id
LEFT JOIN invoice_tags it
ON it.invoice_id = inv.id
LEFT JOIN invoice_transaction_reference itr
ON itr.invoice_id = inv.id
AND itr.rn = 1
LEFT JOIN sale_info si
ON si.invoice_id = inv.id
LEFT JOIN invoice_payments ip
ON ip.invoice_id = inv.id
-- Nur Lieferungen in die Schweiz (Versandland, Fallback: Rechnungsland).
WHERE COALESCE(rc_ship.code, rc_inv.code) = 'CH'
),
-- ===========================================================================
-- AMAZON-Seite
-- ===========================================================================
-- Basiszahlen + effektiver USt-Satz je Transaktionszeile.
amazon_base AS (
SELECT
a.transaction_complete_date,
a.transaction_depart_date,
a.vat_inv_number,
a.sale_arrival_country,
a.arrival_country,
a.transaction_event_id,
a.buyer_vat_number,
a.buyer_name,
a.activity_transaction_id,
COALESCE(a.total_activity_value_amt_vat_incl, 0) AS gross,
COALESCE(a.total_activity_value_amt_vat_excl, 0) AS net,
COALESCE(a.total_ship_charge_amt_vat_incl, 0) AS ship_gross,
COALESCE(a.total_ship_charge_amt_vat_excl, 0) AS ship_net,
CASE
WHEN COALESCE(a.total_activity_value_amt_vat_excl, 0) <> 0
THEN ROUND((COALESCE(a.total_activity_value_vat_amt, 0)
/ a.total_activity_value_amt_vat_excl * 100)::numeric, 2)
ELSE 0
END AS rate
FROM brandize_datacenter_amazon_vat_transaction a
WHERE a.activity_period IN (SELECT activity_period FROM qmonths)
AND a.arrival_country = 'CH'
-- Optional: Gebuehrenzeilen ausschliessen (wie in VAT_Summary.sql):
-- AND a.sales_channel <> 'AMAZON_FEE'
),
amazon_rows AS (
SELECT
TO_CHAR(COALESCE(b.transaction_complete_date, b.transaction_depart_date), 'YYYY-MM-DD')
AS "Rechnungsdatum",
COALESCE(b.vat_inv_number, '') AS "Rechnungsnummer",
COALESCE(rc_inv.name->>'en_US', rc_inv.name->>'de_DE', '') AS "Rechnungsland",
COALESCE(b.sale_arrival_country, '') AS "Rechnungsland Ländercode",
'' AS "Zahlart",
COALESCE(b.transaction_event_id, '') AS "Zahlungsreference der Bestellung",
COALESCE(b.buyer_vat_number, '') AS "USt. Id / VAT Id des Käufers (in Bestellung)",
ROUND(b.gross::numeric, 2) AS "Gesamtpreis brutto",
ROUND(b.net::numeric, 2) AS "Gesamtpreis netto",
CASE
WHEN (b.sale_arrival_country = 'CH' AND b.rate >= 8)
OR (COALESCE(b.sale_arrival_country, '') <> 'CH' AND b.rate >= 16)
THEN ROUND(b.gross::numeric, 2) ELSE 0
END AS "Brutto",
CASE
WHEN NOT (
(b.sale_arrival_country = 'CH' AND b.rate >= 8)
OR (COALESCE(b.sale_arrival_country, '') <> 'CH' AND b.rate >= 16)
)
THEN ROUND(b.gross::numeric, 2) ELSE 0
END AS "Brutto erm",
CASE
WHEN (b.sale_arrival_country = 'CH' AND b.rate >= 8)
OR (COALESCE(b.sale_arrival_country, '') <> 'CH' AND b.rate >= 16)
THEN b.rate ELSE 0
END AS "USt. Satz",
CASE
WHEN NOT (
(b.sale_arrival_country = 'CH' AND b.rate >= 8)
OR (COALESCE(b.sale_arrival_country, '') <> 'CH' AND b.rate >= 16)
)
THEN b.rate ELSE 0
END AS "Ust. Satz erm",
CASE
WHEN (b.sale_arrival_country = 'CH' AND b.rate >= 8)
OR (COALESCE(b.sale_arrival_country, '') <> 'CH' AND b.rate >= 16)
THEN ROUND(b.net::numeric, 2) ELSE 0
END AS "Netto Betrag",
CASE
WHEN NOT (
(b.sale_arrival_country = 'CH' AND b.rate >= 8)
OR (COALESCE(b.sale_arrival_country, '') <> 'CH' AND b.rate >= 16)
)
THEN ROUND(b.net::numeric, 2) ELSE 0
END AS "Netto Betrag erm",
ROUND(b.ship_gross::numeric, 2) AS "Versandkosten brutto",
ROUND(b.ship_net::numeric, 2) AS "Versandkosten netto",
COALESCE(TO_CHAR(b.transaction_depart_date, 'YYYY-MM-DD'), '') AS "Auftragsdatum",
COALESCE(b.activity_transaction_id, '') AS "Bestellnummer",
'' AS "Zahldatum",
COALESCE(b.buyer_name, '') AS "Lieferadresse Name",
'' AS "Tag",
COALESCE(rc_ship.name->>'en_US', rc_ship.name->>'de_DE', '') AS "Lieferland"
FROM amazon_base b
LEFT JOIN res_country rc_inv
ON rc_inv.code = b.sale_arrival_country
LEFT JOIN res_country rc_ship
ON rc_ship.code = b.arrival_country
)
-- ===========================================================================
-- Zusammenfuehrung: ODOO + AMAZON, je Zeile mit Quelle
-- ===========================================================================
SELECT *, 'ODOO' AS "Quelle" FROM odoo_rows
UNION ALL
SELECT *, 'AMAZON' AS "Quelle" FROM amazon_rows
ORDER BY "Rechnungsdatum", "Rechnungsnummer";