Kdor v Odoo prodaja pakete, na primer merilno napravo z dodatki in montažo, delovno mesto s strojno opremo in vzpostavitvijo ali vzdrževalni paket iz več storitev, v ponudbi hkrati potrebuje dvoje: Sestava mora biti navedena v nalogu, da skladišče, tehnika in obračunavanje vedo, kaj se dobavlja. Na izpisu za stranko pa naj se ne v vsakem primeru prikaže vsaka posamezna postavka z vsako posamezno ceno.
Modul OCA sale_product_set omogoča, da z enim klikom vstavite komplete izdelkov (kosovnice za prodajo) v ponudbo. O izgledu izpisa ne odloča. Zato smo razvili modul Sale Product Set Layout (sale_product_set_layout). Napisan je za Odoo 19 in je kot prosta programska oprema pod licenco AGPL-3 brezplačno na voljo na GitHubu:
github.com/Alex0176/odoo-sale-product-set-layout
Vsebina tega prispevka
- Težava: kompleti izdelkov brez vpliva na izgled izpisa
- Kaj modul počne
- Trije načini tiskanja podrobno
- Skrite vrstice in fiksna cena
- Tehnična izvedba
- Namestitev brez neželenih stranskih učinkov
- Uporaba korak za korakom
- Testi
- Omejitve in pravno opozorilo
- Pogosta vprašanja
- Podpora podjetja Biricon IT Services
Težava: kompleti izdelkov brez vpliva na izgled izpisa
Komplet izdelkov je v Odoo pripravljen seznam izdelkov s količinami. Namesto da bi deset artiklov iskali posamično, v ponudbi izberete Dodaj komplet in dobite vse vrstice naenkrat. To prihrani čas in prepreči pozabljene postavke. Modul sale_product_set iz repozitorija OCA/sale-workflow počne prav to; same komplete zagotavlja product_set iz repozitorija OCA/product-attribute.
V praksi ostajajo tri vrzeli:
- Ni prepoznavne skupine. Vrstice kompleta pristanejo v ponudbi kot ohlapne postavke. Po vstavljanju ni več vidno, katere vrstice spadajo skupaj, skupne vsote kompleta pa ni nikjer.
- Ni vpliva na izpis. Včasih naj stranka vidi vsako postavko s ceno, včasih le ceno paketa, včasih le eno samo vrstico. To je odločitev za vsak komplet ali vsako stranko, ne ročno za vsako ponudbo znova.
- Popravki cen so neprijetni. Če naj ima paket fiksno ceno, ki se razlikuje od vsote cen iz cenika, je potrebna popravljalna vrstica. Ta sodi v izračun, ne pa nujno na papir za stranko.
Odoo 19 prinaša gradnike za čisto rešitev: razdelke in podrazdelke v vrsticah ponudbe z možnostma Skrij cene in Skrij sestavo (polji collapse_prices in collapse_composition). Modul poveže komplet izdelkov s temi standardnimi možnostmi, namesto da bi izumljal lastno obliko tiskanja.
Kaj modul počne
- Vstavljanje kompleta kot razdelka. Pomočnik Dodaj komplet ustvari vrstico razdelka z imenom kompleta, na primer 2 × Merilni komplet Standard, in pod njo vstavi vrstice kompleta. Razdelki znotraj kompleta postanejo podrazdelki.
- Način tiskanja za vsak komplet. V kompletu se enkrat določi, kako se tiska. Pri vstavljanju je mogoče način v pomočniku za ta posamezni primer spremeniti.
- Skrivanje vrstic. Posamezne vrstice lahko označite kot Ne tiskaj (pri kompletu: Skrito). Štejejo v vsoto, vendar se ne natisnejo in ne prikažejo v portalu za stranke. Oznaka se s ponudbe prenese na račun.
- Fiksna cena za vrstico kompleta. Vrstica kompleta lahko nosi fiksno ceno na enoto, ki nadomesti ceno iz cenika, na primer za skrit popravek cene.
Brez modula (samo sale_product_set) | Z sale_product_set_layout |
|---|---|
| Vrstice kompleta kot ohlapne postavke | Vrstica razdelka z imenom kompleta, količina v imenu, vrstice pod njo |
| Razdelki v kompletu ostanejo razdelki in pretrgajo strukturo | Razdelki v kompletu postanejo podrazdelki (line_subsection) |
| Izgled izpisa vedno enak | Način tiskanja za vsak komplet, spremenljiv pri vstavljanju |
| Popravek cene viden na ponudbi in računu | Vrstico je mogoče skriti, a šteje v vsoto |
| Cena samo iz cenika | Po izbiri fiksna cena za vrstico kompleta |
| Postavitev se konča pri ponudbi | Postavitev in skrivanje veljata za ponudbo, naročilo, račun in portal za stranke |
Trije načini tiskanja podrobno
Način tiskanja je izbirno polje print_mode pri kompletu izdelkov. Pri vstavljanju se prevede v obe standardni stikali vrstice razdelka. Za to ima modul eno samo, lahko berljivo preslikavo:
# Druckmodus -> (collapse_prices, collapse_composition) der Abschnittszeile
PRINT_MODE_FLAGS = {
"detailed": (False, False),
"total_only": (True, False),
"summary": (False, True),
}
Način (print_mode) | Prikaz v kompletu | Standardna možnost v Odoo | Izgled izpisa |
|---|---|---|---|
detailed | Vsaka vrstica s ceno | brez | Razdelek, vse vrstice z zneskom |
total_only | Vrstice brez cen, samo vsota kompleta | collapse_prices (Skrij cene) | Razdelek z vsoto, vrstice samo z oznako in količino |
summary | Samo ena vrstica z vsoto kompleta | collapse_composition (Skrij sestavo) | Samo vrstica razdelka z vsoto |
Ker modul uporablja standardne možnosti Odoo 19 in ne lastne oblike tiskanja, delujejo ponudba, potrditev naročila, račun in portal za stranke brez prilagojenih predlog poročil. Kdor ima lastne predloge poročil, ki upoštevajo možnosti razdelkov, dobi enako obnašanje.
Skrite vrstice in fiksna cena
Pogost primer: paket ima ceno paketa, ki je pod vsoto posameznih cen. Namesto da bi popačili posamezne cene, uporabite popravljalno vrstico s fiksno ceno (na primer −50,00 € za komplet) in jo skrijete. V zaledju je račun sledljiv, na izpisu pa je navedena cena paketa.
Pomembno za razumevanje: oznaka hide_in_report ne spremeni ničesar pri izračunu. Količina, cena, popust, davek, vsote in knjižbe nastanejo nespremenjeno s standardnim Odoo. Vrstice manjka le na izpisu in v portalu.
- Pri kompletu izdelkov: vrstica kompleta s Skrito in po izbiri Fiksna cena skupaj s ceno na enoto.
- Pri vrsticah ponudbe in računa: stolpec Ne tiskaj (
hide_in_report), tudi za običajne vrstice brez kompleta. - Prenos: Pri ustvarjanju računa iz naloga se oznaka prenese na vrstico računa. Pri kopiranju ponudbe ostane ohranjena.
Tehnična izvedba
Modul je namenoma majhen: razširja obstoječe modele in prepisuje le mesta, kjer Odoo odloča, katere vrstice se natisnejo in kako se komplet vstavi. Ni novih predlog poročil, novih modelov ali posegov v SQL.
Razširjeni modeli in polja
| Model | Dopolnitev |
|---|---|
product.set | Polji insert_as_section (Boolean, privzeto vklopljeno) in print_mode (izbira, obvezno polje, privzeto detailed) |
product.set.line | Polja hide_in_report, fixed_price, price_unit; prepare_sale_order_line_values() jih posreduje vrstici ponudbe |
sale.product.set.wizard | Polja insert_as_section, section_name, print_mode; _prepare_order_lines() sestavi vrstico razdelka |
sale.order / sale.order.line | Polje hide_in_report (s copy=True); _get_order_lines_to_report() preskoči skrite vrstice; _prepare_invoice_line() posreduje oznako naprej |
account.move / account.move.line | Polje hide_in_report; _get_move_lines_to_report(), _get_detailed_lines() in _get_subsection_lines() filtrirajo skrite vrstice; _get_aml_vals() prenese oznako v podatke poročila |
Skrivanje v ponudbi
Odoo 19 vrstice ponudbe za tisk določi v _get_order_lines_to_report(). Modul tam doda filter. Poseg v predlogo poročila ni potreben: tako predloga poročila ponudbe (sale/report/ir_actions_report_templates.xml) kot predloga portala (sale/views/sale_portal_templates.xml) kličeta to metodo:
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
)
Prenos na račun
Pri ustvarjanju vrstice računa iz vrstice ponudbe (_prepare_invoice_line()) se oznaka kopira. Na strani računa je v Odoo 19 več poti, po katerih vrstice pridejo v poročilo: glavni seznam, vrstice razdelka in vrstice podrazdelka. Zato modul filtrira na več mestih (_get_move_lines_to_report() pri dokumentu, _get_detailed_lines() in _get_subsection_lines() pri vrstici), sicer bi se skrita vrstica lahko znova pojavila po eni od drugih poti:
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")]
Pomočnik: razdelek namesto ohlapnih vrstic
Pomočnik sale.product.set.wizard iz sale_product_set ustvari vrstice ponudbe v _prepare_order_lines(). Modul to metodo prepiše. Če je Vstavi kot razdelek izklopljeno, preprosto pokliče izvirno metodo, obnašanje pa ostane kot v modulu OCA. Sicer najprej nastane vrstica razdelka z obema standardnima stikaloma, nato sledijo vrstice kompleta. Razdelki znotraj kompleta postanejo podrazdelki, da ne pretrgajo glavne strukture:
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
Odločitve, ki jih ne vidite
- Ločene računske metode v pomočniku. Ime razdelka, način tiskanja in Vstavi kot razdelek imajo vsak svojo metodo
compute(store=True,readonly=False). Če bi imela vsa tri isto metodo, bi izrecno posredovana vrednost za eno polje ponastavila druga. To je opazno predvsem, ko se pomočnik ustvari iz kode ali testov z vrednostmi. - Ime razdelka s količino. Pri količini, različni od 1, je ta v imenu (2 × Merilni komplet Standard, z vejico kot decimalnim ločilom), da je na izpisu razvidno, da gre za dva kompleta in ne za en komplet z dvojno količino.
- Fiksna cena samo pri vrsticah izdelkov.
prepare_sale_order_line_values()nastavihide_in_reportinprice_unitle, če vrstica kompleta ni vrstica razdelka ali opombe. - Standardni Odoo namesto lastne izdelave. Način tiskanja in skrivanje uporabljata obstoječe kljuke in polja Odoo 19. S tem so posodobitve obvladljive: če Odoo spremeni predlogo poročila, modul ostane veljaven, dokler metode obstajajo.
Namestitev brez neželenih stranskih učinkov
Zahteve: Odoo 19.0, sale_product_set (OCA/sale-workflow, veja 19.0) in product_set (OCA/product-attribute, veja 19.0). Modul sam je odvisen od sale_management, sale_product_set in account.
Past auto_install pri modulih OCA. Številni repozitoriji OCA vsebujejo module z auto_install. Takoj ko so njihove odvisnosti na voljo, jih Odoo ob naslednji namestitvi ali posodobitvi namesti nevprašano. Kdor zato v addons_path produkcijske instance doda celoten repozitorij OCA, morda dobi module, ki jih nihče ni hotel. Pri OCA/product-attribute to na primer zadeva purchase_product_template_tags. Naš postopek:
- Obe repozitorija OCA klonirajte plitvo (
git clone --depth 1 --branch 19.0). - V lastnem imeniku s simbolno povezavo povežite samo dva potrebna modula in ta imenik dodajte v
addons_path, ne celotnih repozitorijev. - Namestite na testno bazo podatkov in preverite, kateri moduli pri tem dobijo stanje nameščen.
- Šele nato namestite produkcijsko, z
--workers=0, da klic ne tekmuje s tekočo storitvijo za vrata HTTP.
odoo-bin -c /etc/odoo/odoo.conf -d <datenbank> -i sale_product_set_layout --stop-after-init
Nova polja in pogledi so po namestitvi v bazi podatkov. Če storitev teče v večprocesnem načinu, delavci spremenjeni register naložijo prek signala baze podatkov. Spremembe datotek Python modula začnejo veljati šele po ponovnem zagonu storitve.
Uporaba korak za korakom
- Ustvarjanje kompleta: Prodaja → Izdelki → Kompleti izdelkov. Komplet poimenujte, izberite Vstavi kot razdelek in Način tiskanja, vnesite izdelke s količinami. Popravljalne vrstice opremite s Skrito in Fiksna cena.
- V ponudbi: Kliknite Dodaj komplet, izberite komplet in količino. Ime razdelka in način tiskanja je mogoče pred vstavljanjem spremeniti.
- Skrivanje posameznih vrstic: V ponudbi ali računu vklopite stolpec Ne tiskaj.
- Preverjanje: Odprite predogled ali PDF. Enak prikaz vidijo stranke v portalu.
Testi
Modul vsebuje šest avtomatiziranih testov, ki jih zaženemo na testni bazi podatkov, preden gre karkoli v produkcijo:
- Vstavljanje kot razdelek vključno z načinom tiskanja in podrazdelkom
- Skrite vrstice ni med vrsticami za tisk
- Način Ena vrstica (
summary) - Vstavljanje brez razdelka, izvirno obnašanje
- Račun prevzame oznako
hide_in_report, vrstice ni v_get_move_lines_to_report(), vsota razdelka jo še vedno vsebuje - Račun v načinu Samo skupna cena ne prikaže skrite vrstice med vrsticami razdelka, vsota razdelka ostane popolna
odoo-bin -d <testdatenbank> -i sale_product_set_layout \
--test-enable --test-tags=/sale_product_set_layout --stop-after-init
Nemški prevod je v i18n/de.po.
Omejitve in pravno opozorilo
- Samo postavitev. Modul ne spreminja, kako Odoo izračunava cene, popuste ali davke. Spreminja le, kaj se natisne in prikaže v portalu.
- Skrite vrstice so v zaledju vidne. Oznaka zadeva izpis in portal, ne prikaza na zaslonu za zaposlene.
- Preverite podatke na računu. Skrite vrstice štejejo v vsoto, vendar niso na dokumentu. Ali je to združljivo z zahtevami za račune v vaši državi, na primer s predpisanim opisom dobavljenih predmetov ali opravljenih storitev, naj bi pred uporabo na računih razčistili s svojim davčnim svetovalcem. Na ponudbah je skrivanje manj problematično. Prispevek ni pravno svetovanje.
- Testirano za Odoo 19. Modul smo razvili in testirali za Odoo 19.0 Community. Uporablja možnosti razdelkov, ki so v tej obliki prisotne v Odoo 19. Za druge različice ga nismo preverjali.
Pogosta vprašanja
Zakaj potrebujem modul, če Odoo 19 že pozna razdelke?
Možnosti razdelkov so v samem Odoo. Manjkala je povezava s kompletom izdelkov: komplet naj bi se samodejno vstavil kot razdelek z načinom tiskanja, shranjenim v kompletu. Brez modula je treba po vsakem vstavljanju vrstico razdelka ročno ustvariti in nastaviti.
Kako se razlikujeta „Skrij cene“ in „Skrij sestavo“?
„Skrij cene“ (collapse_prices) pusti vrstice, vendar ne prikaže zneskov, samo vsoto pri razdelku. „Skrij sestavo“ (collapse_composition) vrstice povsem skrije, stranka vidi samo razdelek z vsoto.
Ali skrita vrstica šteje v vsoto računa?
Da. Skrite vrstice ostanejo v vsoti, davku in knjižbi. Oznaka zadeva samo prikaz na izpisu in v portalu za stranke.
Ali lahko način tiskanja pri vstavljanju še spremenim?
Da. Način je prednastavljen iz kompleta, v pomočniku ga je mogoče za posamezno vstavljanje spremeniti. Komplet sam pri tem ostane nespremenjen.
Kaj se zgodi, če izklopim Vstavi kot razdelek?
Potem se pomočnik obnaša kot v modulu OCA sale_product_set: vrstice kompleta se vstavijo brez razdelka.
Ali modul nepričakovano namesti dodatne module?
Modul sam ne. Pri repozitorijih OCA pa lahko pride do modulov z auto_install, če v addons_path dodate celotne repozitorije. Zato povežite samo oba potrebna modula (glejte razdelek Namestitev).
Ali modul deluje z Odoo Enterprise?
Modul je odvisen samo od modulov Community (sale_management, account) in obeh modulov OCA. Uporabljamo ga na Odoo 19 Community. Na Enterprise ga nismo testirali.
Pod katero licenco je modul?
Pod AGPL-3. Smete ga uporabljati, prilagajati in posredovati naprej, dokler spremembe ostanejo pod isto licenco. Napake in predloge izboljšav so dobrodošli kot issue v repozitoriju GitHub .
Podpora podjetja Biricon IT Services
Oskrbujemo namestitve Odoo za mala in srednja podjetja: od uvedbe prek prilagoditev in migracij do tekočega obratovanja. Če želite kompleti izdelkov, predloge ponudb ali poročila v Odoo 19 prilagoditi svojim postopkom ali če želite pregledati tak modul in ga varno prenesti v svojo produkcijsko instanco, vam z veseljem pomagamo. Druge lastne razvoje najdete v našem blogu, na primer Združevanje osnutkov računov in Samodejno prirejanje bančnih plačil računom.
Stanje: 2. november 2026. Različica modula 19.0.1.0.0. Vzorčni podatki na slikah so poljubno izbrani, zneski neto.