Wien an Odoo Pakéiten verkeeft, zum Beispill e Miessgeräit mat Zubehör a Montage, eng Aarbechtsplaz mat Hardware an Ariichtung oder e Wartungspak aus méi Leeschtungen, brauch am Offert zwou Saachen op eemol: D'Zesummesetzung muss am Optrag stoen, datt Lager, Technik a Rechnungsstellung wëssen, wat geliwwert gëtt. Um Ausdrock fir de Client soll awer net a jidde Fall all Eenzelposition mat all Eenzelpräis erschéngen.
Den OCA-Modul sale_product_set erlaabt et, Produkt-Sets (Stécklëschte fir de Verkaf) mat engem Klick an en Offert anzefügen. Iwwert d'Dréckbild entscheet hien net. Dofir hu mir de Modul Sale Product Set Layout (sale_product_set_layout) entwéckelt. Hien ass fir Odoo 19 geschriwwen a steet als fräi Software ënner der AGPL-3-Lizenz gratis op GitHub zur Verfügung:
github.com/Alex0176/odoo-sale-product-set-layout
Inhalt vun dësem Bäitrag
- De Problem: Produkt-Sets ouni Afloss op d'Dréckbild
- Wat de Modul mécht
- Déi dräi Dréckmodi am Detail
- Verstoppte Zeilen a Festpräis
- Technesch Ëmsetzung
- Installatioun ouni ongewollt Niewewierkungen
- Bedienung Schrëtt fir Schrëtt
- Tester
- Grenzen a rechtlechen Hiweis
- Heefeg Froen
- Ënnerstëtzung duerch Biricon IT Services
De Problem: Produkt-Sets ouni Afloss op d'Dréckbild
E Produkt-Set ass an Odoo eng virbereet Lëscht vu Produkter mat Mengen. Amplaz zéng Artikelen eenzel ze sichen, wielt een am Offert Set derbäisetzen a kritt all Zeilen op eemol. Dat spuert Zäit a verhënnert vergiessene Positiounen. Den Modul sale_product_set aus dem Repository OCA/sale-workflow mécht genee dat; d'Sets selwer stamen aus product_set am Repository OCA/product-attribute.
An der Praxis bleiwen dräi Lücken:
- Keng erkennbar Gruppéierung. D'Set-Zeile landen als lass Positiounen am Offert. Nom Afügen gesäit een net méi, wéi eng Zeile zesummegehéieren, an d'Gesamtsumm vum Set steet néierens.
- Kee Afloss op den Ausdrock. Heiansdo soll de Client all Positioun mat Präis gesinn, heiansdo nëmmen de Pakpräis, heiansdo nëmmen eng eenzeg Zeil. Dat ass eng Entscheedung pro Set oder pro Client, net all Kéier nei per Hand pro Offert.
- Präiskorrekture sinn onschéin. Soll e Pak e fixe Präis hunn, deen vun der Summ vun de Lëschtepräisser ofwäicht, brauch et eng Korrekturzeil. Déi gehéiert an d'Berechnung, awer net onbedéngt op d'Pabeier vum Client.
Odoo 19 bréngt d'Bausteng mat, fir dat propper ze léisen: Abschnitter an Ënnerabschnitter an Offertzeilen mat den Optioune Präisser verstoppen an Zesummesetzung verstoppen (Felder collapse_prices an collapse_composition). Den Modul verbënnt de Produkt-Set mat dëse Standard-Optiounen, amplaz e ganz eegent Dréckformat ze erfannen.
Wat de Modul mécht
- Set als Abschnitt afügen. Den Assistent Set derbäisetzen leet eng Abschnittszeil mam Numm vum Set un, zum Beispill 2 × Messkit Standard, a setzt d'Set-Zeilen drënner. Abschnitter am Set ginn zu Ënnerabschnitter.
- Dréckmodus pro Set. Am Set gëtt eemol festgeluecht, wéi et gedréckt gëtt. Beim Afügen léisst sech de Modus am Assistent fir dësen eenzele Fall änneren.
- Zeilen verstoppen. Eenzel Zeile kënnen als Net drécken (um Set: Verstoppt) markéiert ginn. Si zielen an der Summ mat, ginn awer weder gedréckt nach am Clientenportal ugewisen. D'Kennzeechen wandert vum Offert op d'Rechnung.
- Festpräis pro Set-Zeil. Eng Set-Zeil kann e fixen Eenzelpräis droen, deen de Präis aus der Präisslëscht ersetzt, zum Beispill fir eng verstoppte Präiskorrektur.
Ouni de Modul (nëmmen sale_product_set) | Mat sale_product_set_layout |
|---|---|
| Set-Zeile als lass Positiounen | Abschnittszeil mam Set-Numm, Quantitéit am Numm, Zeile drënner |
| Abschnitter am Set bleiwen Abschnitter a zerräissen d'Struktur | Abschnitter am Set ginn Ënnerabschnitter (line_subsection) |
| Dréckbild ëmmer d'selwecht | Dréckmodus pro Set, beim Afügen ännerbar |
| Präiskorrektur sichtbar op Offert a Rechnung | Zeil verstoppbar, zielt awer an der Summ mat |
| Präis nëmmen aus der Präisslëscht | Optional Festpräis pro Set-Zeil |
| Layout endet um Offert | Layout a Verstoppe gëllen fir Offert, Optrag, Rechnung a Clientenportal |
Déi dräi Dréckmodi am Detail
Den Dréckmodus ass e Auswielfeld print_mode um Produkt-Set. En gëtt beim Afügen an déi zwee Standard-Schalter vun der Abschnittszeil iwwersat. Dofir steet am Modul eng eenzeg, einfach liesbar Zuuerdnung:
# Druckmodus -> (collapse_prices, collapse_composition) der Abschnittszeile
PRINT_MODE_FLAGS = {
"detailed": (False, False),
"total_only": (True, False),
"summary": (False, True),
}
Modus (print_mode) | Usiicht am Set | Standard-Optioun an Odoo | Dréckbild |
|---|---|---|---|
detailed | All Zeil mat Präis | keng | Abschnitt, all Zeile mat Betrag |
total_only | Zeile ouni Präisser, nëmmen d'Set-Summ | collapse_prices (Präisser verstoppen) | Abschnitt mat Summ, Zeile nëmme mat Bezeechnung a Quantitéit |
summary | Nëmmen eng Zeil mat der Set-Summ | collapse_composition (Zesummesetzung verstoppen) | Nëmmen d'Abschnittszeil mat der Summ |
Well den Modul déi Standard-Optioune vun Odoo 19 benotzt an keen eegent Dréckformat, funktionéieren Offert, Optragsbestätegung, Rechnung a Clientenportal ouni ugepasste Berichtsvirlagen. Wien eege Berichtsvirlagen huet, déi d'Abschnitts-Optiounen berécksiichtegen, kritt d'Verhalen och.
Verstoppte Zeilen a Festpräis
E heefege Fall: E Pak huet e Pakpräis, deen ënner der Summ vun den Eenzelpräisser läit. Amplaz d'Eenzelpräisser ze verbéien, hëlt een eng Korrekturzeil mat Festpräis (zum Beispill −50,00 € pro Set) a verstoppt se. Am Backend ass d'Rechnung nozevollzéien, um Ausdrock steet de Pakpräis.
Wichteg fir d'Verständnis: D'Kennzeechen hide_in_report ännert näischt un der Berechnung. Quantitéit, Präis, Rabatt, Steier, Summen a Buchungssätz entstinn onverännert duerch Standard-Odoo. D'Zeil feelt nëmmen um Ausdrock an um Portal.
- Um Produkt-Set: Set-Zeil mat Verstoppt an optional Festpräis mat Eenzelpräis.
- An Offert- a Rechnungszeilen: Kolonn Net drécken (
hide_in_report), och fir normal Zeilen ouni Set. - Weidergab: Beim Erstellen vun der Rechnung aus dem Optrag gëtt d'Kennzeechen op d'Rechnungszeil iwwerdroen. Beim Kopéiere vun engem Offert bleift et erhalen.
Technesch Ëmsetzung
De Modul ass bewosst kleng: Hien erweidert existent Modeller an iwwerschreift nëmmen déi Stellen, un deenen Odoo entscheet, wéi eng Zeile gedréckt ginn a wéi e Set agefüügt gëtt. Et gëtt keng nei Berichtsvirlagen, keng nei Modeller a keng SQL-Agrëffer.
Erweidert Modeller a Felder
| Modell | Zousaz |
|---|---|
product.set | Felder insert_as_section (Boolean, Standard un) an print_mode (Auswiel, Pflichtfeld, Standard detailed) |
product.set.line | Felder hide_in_report, fixed_price, price_unit; prepare_sale_order_line_values() gëtt se un d'Offertzeil weider |
sale.product.set.wizard | Felder insert_as_section, section_name, print_mode; _prepare_order_lines() baut d'Abschnittszeil op |
sale.order / sale.order.line | Feld hide_in_report (mat copy=True); _get_order_lines_to_report() iwwersprëngt verstoppte Zeilen; _prepare_invoice_line() gëtt d'Kennzeechen weider |
account.move / account.move.line | Feld hide_in_report; _get_move_lines_to_report(), _get_detailed_lines() an _get_subsection_lines() filteren verstoppte Zeilen; _get_aml_vals() dréit d'Kennzeechen an d'Berichtsdaten |
Verstoppen am Offert
Odoo 19 ermëttelt déi ze dréckend Offertzeilen an _get_order_lines_to_report(). De Modul hänkt do e Filter un. En Agrëff an d'Berichtsvirlag ass net néideg: Souwuel d'Berichtsvirlag vum Offert (sale/report/ir_actions_report_templates.xml) wéi och d'Portalvirlag (sale/views/sale_portal_templates.xml) ruffen dës Method op:
class SaleOrder(models.Model):
_inherit = "sale.order"
def _get_order_lines_to_report(self):
return super()._get_order_lines_to_report().filtered(
lambda line: not line.hide_in_report
)
Weidergab op d'Rechnung
Beim Erzeege vun der Rechnungszeil aus der Offertzeil (_prepare_invoice_line()) gëtt d'Kennzeechen kopéiert. Op der Rechnungssäit gëtt et an Odoo 19 méi Weeër, iwwer déi Zeilen an de Bericht kommen: d'Haaptlëscht, d'Zeile vun engem Abschnitt an d'Zeile vun engem Ënnerabschnitt. Dofir filtert de Modul u verschiddene Stellen (_get_move_lines_to_report() um Beleg, _get_detailed_lines() an _get_subsection_lines() bei der Zeil), soss kéint eng verstoppte Zeil iwwer ee vun deenen aneren Weeër erëm opdauchen:
class AccountMoveLine(models.Model):
_inherit = "account.move.line"
hide_in_report = fields.Boolean(string="Hidden in report")
def _get_aml_vals(self, hide_taxes):
res = super()._get_aml_vals(hide_taxes)
res["hide_in_report"] = self.hide_in_report
return res
def _get_detailed_lines(self, children_lines, direct_children_lines, subsection_lines):
res = super()._get_detailed_lines(children_lines, direct_children_lines, subsection_lines)
return [vals for vals in res if not vals.get("hide_in_report")]
def _get_subsection_lines(self, subsection_line, children_lines):
res = super()._get_subsection_lines(subsection_line, children_lines)
return [vals for vals in res if not vals.get("hide_in_report")]
Den Assistent: Abschnitt amplaz vu losse Zeilen
Den Assistent sale.product.set.wizard aus sale_product_set erstellt d'Offertzeilen an _prepare_order_lines(). De Modul iwwerschreift dës Method. Ass Als Abschnitt afügen aus, rifft hien einfach déi ursprénglech Method op, d'Verhale bleift dann wéi am OCA-Modul. Soss entsteet fir d'éischt d'Abschnittszeil mat den zwee Standard-Schalter, duerno folge d'Set-Zeilen. Abschnitter am Set ginn zu Ënnerabschnitter, domat si d'Haaptstruktur net zerräissen:
def _prepare_order_lines(self):
if not self.insert_as_section:
return super()._prepare_order_lines()
sequence = self._get_max_sequence() + 1
collapse_prices, collapse_composition = PRINT_MODE_FLAGS[self.print_mode or "detailed"]
order_lines = [Command.create({
"display_type": "line_section",
"name": self.section_name or self.product_set_id.name,
"sequence": sequence,
"collapse_prices": collapse_prices,
"collapse_composition": collapse_composition,
})]
for set_line in self._get_lines():
sequence += 1
values = set_line.prepare_sale_order_line_values(self.order_id, self.quantity, sequence)
if values.get("display_type") == "line_section":
values["display_type"] = "line_subsection"
order_lines.append(Command.create(values))
return order_lines
Decisiounen, déi een net gesäit
- Getrennte Berechnungsmethoden am Assistent. Abschnittsnumm, Dréckmodus an Als Abschnitt afügen hunn all eng eege
compute-Method (store=True,readonly=False). Hätte se all dräi déiselwecht Method, géif en explizit iwwergebene Wert fir ee Feld déi anerer zerécksetzen. Dat fält virun allem op, wann den Assistent aus Code oder Tester mat Wäerter ugeluecht gëtt. - Abschnittsnumm mat Quantitéit. Bei enger Quantitéit ongläich 1 steet si am Numm (2 × Messkit Standard, mat Komma als Dezimaltrenner), fir datt een um Ausdrock erkennt, datt et zwee Sets sinn an net ee Set mat duebeler Quantitéit.
- Festpräis nëmmen un de Produktzeilen.
prepare_sale_order_line_values()setzthide_in_reportanprice_unitnëmmen, wann d'Set-Zeil keng Abschnitts- oder Notizzeil ass. - Standard-Odoo amplaz Eegebau. Dréckmodus a Verstoppe benotzen existent Hooks a Felder vun Odoo 19. Dat mécht Updates beherrschbar: Ännert Odoo d'Berichtsvirlag, bleift de Modul gëlteg, soulaang d'Methoden bestoe bleiwen.
Installatioun ouni ongewollt Niewewierkungen
Viraussetzungen: Odoo 19.0, sale_product_set (OCA/sale-workflow, Branch 19.0) an product_set (OCA/product-attribute, Branch 19.0). De Modul selwer hänkt vu sale_management, sale_product_set an account of.
D'auto_install-Fal bei OCA-Moduler. Vill OCA-Repositories enthalen Moduler mat auto_install. Soubal hir Ofhängegkeeten do sinn, installéiert Odoo se bei der nächster Installatioun oder Aktualiséierung ongefrot mat. Wien dofir de komplette OCA-Repository an den addons_path vun enger Produktivinstanz leet, kritt wahrscheinlech Moduler, déi keen wollt hunn. Bei OCA/product-attribute betrëfft dat zum Beispill purchase_product_template_tags. Eis Virgoensweis:
- D'zwee OCA-Repositories flaach klonen (
git clone --depth 1 --branch 19.0). - An engem eegene Verzeechnes nëmmen déi zwee néideg Moduler per Symlink verlinken an dëst Verzeechnes an den
addons_pathopnemmen, net déi ganz Repositories. - Op enger Testdatebank installéieren a préifen, wéi eng Moduler dobäi de Status installéiert kréien.
- Eréischt dann produktiv installéieren, mat
--workers=0, datt den Opruff net mam lafenden Déngscht ëm den HTTP-Port konkurréiert.
odoo-bin -c /etc/odoo/odoo.conf -d <datenbank> -i sale_product_set_layout --stop-after-init
Nei Felder an Usiichte sinn nom Installéiere an der Datebank. Leeft den Déngscht am Méiprozessbetrib, lued d'Worker déi geännert Registry iwwer d'Datebank-Signal nei. Ännerungen un de Python-Dateie vum Modul ginn eréischt no engem Neistart vum Déngscht wierksam.
Bedienung Schrëtt fir Schrëtt
- Set uleeën: Verkaf → Produkter → Produkt-Sets. Set benennen, Als Abschnitt afügen an Dréckmodus wielen, d'Produkter mat Mengen aginn. Korrekturzeile mat Verstoppt a Festpräis versinn.
- Am Offert: Op Set derbäisetzen klicken, Set a Quantitéit wielen. Abschnittsnumm an Dréckmodus loossen sech virum Afügen änneren.
- Eenzel Zeilen verstoppen: Am Offert oder an der Rechnung d'Kolonn Net drécken aktivéieren.
- Préifen: Virschau oder PDF opmaachen. Déiselwecht Duerstellung gesinn d'Clienten um Portal.
Tester
De Modul bréngt sechs automatiséiert Tester mat, déi mir géint eng Testdatebank ausféieren, éier eppes produktiv geet:
- Afügen als Abschnitt inklusiv Dréckmodus an Ënnerabschnitt
- Verstoppte Zeil feelt an de ze dréckenden Zeilen
- Modus Eng Zeil (
summary) - Afügen ouni Abschnitt, dat ursprénglecht Verhalen
- Rechnung iwwerhëlt d'Kennzeechen
hide_in_report, d'Zeil feelt an_get_move_lines_to_report(), d'Abschnittssumm enthält se weiderhin - Rechnung am Modus Nëmmen Gesamtpräis weist déi verstoppte Zeil net an den Abschnittszeilen, d'Abschnittssumm bleift komplett
odoo-bin -d <testdatenbank> -i sale_product_set_layout \
--test-enable --test-tags=/sale_product_set_layout --stop-after-init
Déi däitsch Iwwersetzung läit an i18n/de.po.
Grenzen a rechtlechen Hiweis
- Nëmmen Layout. De Modul ännert net, wéi Odoo Präisser, Rabatter oder Steieren berechent. Hien ännert nëmmen, wat gedréckt an um Portal ugewise gëtt.
- Verstoppte Zeile si am Backend sichtbar. D'Kennzeechen betrëfft Ausdrock a Portal, net d'Bildschirmusiicht vun de Mataarbechter.
- Rechnungsangabe préifen. Verstoppte Zeile zielen an der Summ mat, stinn awer net um Beleg. Ob dat mat den Ufuerderunge un Rechnungen an Ärem Land vereinbar ass, zum Beispill mat der virgeschriwwener Beschreiwung vun de geliwwerte Géigestänn oder erbrachte Leeschtungen, sollt Dir virum Asaz op Rechnungen mat Ärer Steierberodung klären. Op Offerte ass d'Verstoppe manner problematesch. De Bäitrag ass keng Rechtsberodung.
- Getest fir Odoo 19. Entwéckelt a getest hu mir de Modul fir Odoo 19.0 Community. Hien notzt Abschnitts-Optiounen, déi an dëser Form an Odoo 19 do sinn. Fir aner Versioune hu mir en net gepréift.
Heefeg Froen
Wouzou brauch ech de Modul, wann Odoo 19 schonn Abschnitter kann?
D'Abschnitts-Optioune gëtt et an Odoo selwer. Et huet d'Verbindung zum Produkt-Set gefeelt: E Set sollt automatesch als Abschnitt agefüügt ginn, mat deem am Set hannerleete Dréckmodus. Ouni de Modul muss een no all Afügen d'Abschnittszeil vun Hand uleeën a konfiguréieren.
Wéi ennerscheede sech „Präisser verstoppen“ a „Zesummesetzung verstoppen“?
„Präisser verstoppen“ (collapse_prices) léisst d'Zeilen stoen, weist awer keng Beträg, nëmmen d'Summ um Abschnitt. „Zesummesetzung verstoppen“ (collapse_composition) verstoppt d'Zeilen ganz, de Client gesäit nëmmen den Abschnitt mat der Summ.
Zielt eng verstoppte Zeil an der Rechnungssumm mat?
Jo. Verstoppte Zeile bleiwen a Summ, Steier a Buchung. D'Kennzeechen betrëfft nëmmen d'Duerstellung um Ausdrock an am Clientenportal.
Kann ech den Dréckmodus beim Afügen nach änneren?
Jo. De Modus kënnt als Virgab aus dem Set, am Assistent kann en fir dat jeweilegt Afügen geännert ginn. D'Set selwer bleift dobäi onverännert.
Wat geschitt, wann ech Als Abschnitt afügen ausschalten?
Dann verhält sech den Assistent wéi am OCA-Modul sale_product_set: D'Set-Zeile ginn ouni Abschnitt agefüügt.
Installéiert de Modul onerwaart weider Moduler?
De Modul selwer net. Bei OCA-Repositories kann et awer zu auto_install-Moduler kommen, wann ee ganz Repositories an den addons_path leet. Verlinkt dofir nëmmen déi zwee néideg Moduler (kuckt Abschnitt Installatioun).
Leeft de Modul mat Odoo Enterprise?
De Modul hänkt nëmmen vu Community-Moduler of (sale_management, account) an den zwee OCA-Moduler. Mir setzen en op Odoo 19 Community an. Op Enterprise hu mir en net getest.
Ënner wéi enger Lizenz steet de Modul?
Ënner der AGPL-3. Dir däerft en notzen, upassen a weiderginn, soulaang Ännerunge ënner derselwechter Lizenz bleiwen. Feeler a Verbesserungsvirschléi si als Issue am GitHub-Repository wëllkomm.
Ënnerstëtzung duerch Biricon IT Services
Mir betreie Odoo-Installatioune fir kleng a mëttelgrouss Betriber: vun der Aféierung iwwer Upassungen a Migratiounen bis zum lafenden Betrib. Wann Dir Produkt-Sets, Offertvirlagen oder Berichter an Odoo 19 un Är Ofleef upasse wëllt, oder wann Dir e Modul wéi dëse préife a sécher an Är Produktivinstanz bréngen wëllt, ënnerstëtzen mir Iech gär. Weider Eegenentwécklunge fannt Dir an eisem Blog, zum Beispill Entworfsrechnungen zesummeféieren a Bankzuelungen automatesch Rechnungen zuuerdnen.
Stand: 2. November 2026. Modulversioun 19.0.1.0.0. D'Beispilldaten an den Abbildunge si fräi gewielt, Beträg netto.