Ko u Odoou prodaje pakete, na primer mernu opremu sa priborom i montažom, radno mesto sa hardverom i podešavanjem ili paket održavanja od više usluga, treba u ponudi istovremeno dve stvari: Sastav mora da stoji u nalogu, kako bi skladište, tehnika i fakturisanje znali šta se isporučuje. Na štampanom primerku za klijenta međutim ne treba u svakom slučaju da se pojavi svaka pojedinačna stavka sa svakom pojedinačnom cenom.
OCA modul sale_product_set omogućava da se setovi proizvoda (sastavnice za prodaju) jednim klikom umetnu u ponudu. O izgledu štampe on ne odlučuje. Zato smo razvili modul Sale Product Set Layout (sale_product_set_layout). Napisan je za Odoo 19 i besplatno je dostupan na GitHubu kao slobodan softver pod AGPL-3 licencom:
github.com/Alex0176/odoo-sale-product-set-layout
Sadržaj ovog članka
- Problem: setovi proizvoda bez uticaja na izgled štampe
- Šta modul radi
- Tri režima štampe detaljno
- Skriveni redovi i fiksna cena
- Tehnička realizacija
- Instalacija bez neželjenih sporednih efekata
- Upotreba korak po korak
- Testovi
- Ograničenja i pravna napomena
- Česta pitanja
- Podrška kompanije Biricon IT Services
Problem: setovi proizvoda bez uticaja na izgled štampe
Set proizvoda je u Odoou unapred pripremljena lista proizvoda sa količinama. Umesto da se deset artikala traži pojedinačno, u ponudi se izabere Dodaj set i svi redovi se dobiju odjednom. To štedi vreme i sprečava zaboravljene stavke. Modul sale_product_set iz repozitorijuma OCA/sale-workflow radi upravo to; sami setovi potiču iz product_set u repozitorijumu OCA/product-attribute.
U praksi ostaju tri praznine:
- Nema prepoznatljivog grupisanja. Redovi seta završavaju kao slobodne stavke u ponudi. Posle umetanja se više ne vidi koji redovi zajedno pripadaju, a ukupan iznos seta nigde ne stoji.
- Nema uticaja na štampu. Čas klijent treba da vidi svaku stavku sa cenom, čas samo cenu paketa, čas samo jedan jedini red. To je odluka po setu ili po klijentu, a ne nešto što se za svaku ponudu iznova radi ručno.
- Korekcije cena su neugodne. Ako paket treba da ima fiksnu cenu koja odstupa od zbira cena iz cenovnika, potreban je korekcioni red. On pripada obračunu, ali ne nužno i papiru klijenta.
Odoo 19 donosi građevne elemente da se ovo čisto reši: odeljke i pododeljke u redovima ponude sa opcijama Sakrij cene i Sakrij sastav (polja collapse_prices i collapse_composition). Modul povezuje set proizvoda sa ovim standardnim opcijama, umesto da izmišlja sopstveni format štampe.
Šta modul radi
- Umetanje seta kao odeljka. Čarobnjak Dodaj set pravi red odeljka sa nazivom seta, na primer 2 × Merni komplet Standard, i ispod njega postavlja redove seta. Odeljci unutar seta postaju pododeljci.
- Režim štampe po setu. U setu se jednom određuje kako će se štampati. Pri umetanju se režim u čarobnjaku može promeniti za taj jedan slučaj.
- Skrivanje redova. Pojedinačni redovi mogu da se označe kao Ne štampaj (u setu: Skriveno). Ulaze u zbir, ali se ne štampaju niti prikazuju u portalu za klijente. Oznaka se sa ponude prenosi na fakturu.
- Fiksna cena po redu seta. Red seta može da nosi fiksnu pojedinačnu cenu koja zamenjuje cenu iz cenovnika, na primer za skrivenu korekciju cene.
Bez modula (samo sale_product_set) | Sa sale_product_set_layout |
|---|---|
| Redovi seta kao slobodne stavke | Red odeljka sa nazivom seta, količina u nazivu, redovi ispod |
| Odeljci u setu ostaju odeljci i kidaju strukturu | Odeljci u setu postaju pododeljci (line_subsection) |
| Izgled štampe uvek isti | Režim štampe po setu, može se promeniti pri umetanju |
| Korekcija cene vidljiva na ponudi i fakturi | Red se može sakriti, a ipak ulazi u zbir |
| Cena samo iz cenovnika | Opciono fiksna cena po redu seta |
| Izgled se završava na ponudi | Izgled i skrivanje važe za ponudu, nalog, fakturu i portal za klijente |
Tri režima štampe detaljno
Režim štampe je polje za izbor print_mode na setu proizvoda. Pri umetanju se prevodi u dva standardna prekidača reda odeljka. Za to u modulu postoji jedno jedino, lako čitljivo mapiranje:
# Druckmodus -> (collapse_prices, collapse_composition) der Abschnittszeile
PRINT_MODE_FLAGS = {
"detailed": (False, False),
"total_only": (True, False),
"summary": (False, True),
}
Režim (print_mode) | Prikaz u setu | Standardna opcija u Odoou | Izgled štampe |
|---|---|---|---|
detailed | Svaki red sa cenom | nijedno | Odeljak, svi redovi sa iznosom |
total_only | Redovi bez cena, samo zbir seta | collapse_prices (Sakrij cene) | Odeljak sa zbirom, redovi samo sa nazivom i količinom |
summary | Samo jedan red sa zbirom seta | collapse_composition (Sakrij sastav) | Samo red odeljka sa zbirom |
Pošto modul koristi standardne opcije Odoo 19, a ne sopstveni format štampe, ponuda, potvrda narudžbine, faktura i portal za klijente rade bez prilagođenih šablona izveštaja. Ko ima sopstvene šablone izveštaja koji uzimaju u obzir opcije odeljaka, dobija isto ponašanje.
Skriveni redovi i fiksna cena
Čest slučaj: paket ima cenu paketa koja je ispod zbira pojedinačnih cena. Umesto da se pojedinačne cene krive, uzima se korekcioni red sa fiksnom cenom (na primer −50,00 € po setu) i sakriva se. U pozadinskom delu (backend) faktura je razumljiva, a na štampanom primerku stoji cena paketa.
Važno za razumevanje: oznaka hide_in_report ništa ne menja u obračunu. Količina, cena, popust, porez, zbirovi i knjiženja nastaju nepromenjeno u standardnom Odoou. Red samo nedostaje na štampanom primerku i u portalu.
- Na setu proizvoda: red seta sa Skriveno i opciono Fiksna cena zajedno sa Pojedinačnom cenom.
- Na redovima ponude i fakture: kolona Ne štampaj (
hide_in_report), takođe za obične redove bez seta. - Prosleđivanje: pri kreiranju fakture iz naloga oznaka se prenosi na red fakture. Pri kopiranju ponude ona ostaje sačuvana.
Tehnička realizacija
Modul je namerno mali: proširuje postojeće modele i prepisuje samo mesta na kojima Odoo odlučuje koji se redovi štampaju i kako se set umeće. Nema novih šablona izveštaja, nema novih modela i nema zahvata u SQL.
Prošireni modeli i polja
| Model | Dopuna |
|---|---|
product.set | Polja insert_as_section (Boolean, podrazumevano uključeno) i print_mode (izbor, obavezno polje, podrazumevano detailed) |
product.set.line | Polja hide_in_report, fixed_price, price_unit; prepare_sale_order_line_values() ih prosleđuje redu ponude |
sale.product.set.wizard | Polja insert_as_section, section_name, print_mode; _prepare_order_lines() gradi red odeljka |
sale.order / sale.order.line | Polje hide_in_report (sa copy=True); _get_order_lines_to_report() preskače skrivene redove; _prepare_invoice_line() prosleđuje oznaku |
account.move / account.move.line | Polje hide_in_report; _get_move_lines_to_report(), _get_detailed_lines() i _get_subsection_lines() filtriraju skrivene redove; _get_aml_vals() upisuje oznaku u podatke izveštaja |
Skrivanje u ponudi
Odoo 19 određuje redove ponude za štampu u _get_order_lines_to_report(). Modul tu dodaje filter. Zahvat u šablon izveštaja nije potreban: i šablon izveštaja ponude (sale/report/ir_actions_report_templates.xml) i šablon portala (sale/views/sale_portal_templates.xml) pozivaju ovaj metod:
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
)
Prosleđivanje na fakturu
Pri kreiranju reda fakture iz reda ponude (_prepare_invoice_line()) oznaka se kopira. Na strani fakture u Odoou 19 postoji više puteva kojima redovi dospevaju u izveštaj: glavna lista, redovi odeljka i redovi pododeljka. Zato modul filtrira na više mesta (_get_move_lines_to_report() na dokumentu, _get_detailed_lines() i _get_subsection_lines() na redu), inače bi se skriveni red mogao ponovo pojaviti preko jednog od ostalih puteva:
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")]
Čarobnjak: odeljak umesto slobodnih redova
Čarobnjak sale.product.set.wizard iz modula sale_product_set pravi redove ponude u _prepare_order_lines(). Modul prepisuje ovaj metod. Ako je Umetni kao odeljak isključeno, jednostavno poziva originalni metod i ponašanje ostaje kao u OCA modulu. U suprotnom prvo nastaje red odeljka sa dva standardna prekidača, a zatim slede redovi seta. Odeljci unutar seta postaju pododeljci kako ne bi kidali glavnu strukturu:
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
Odluke koje se ne vide
- Odvojeni metodi izračunavanja u čarobnjaku. Naziv odeljka, režim štampe i Umetni kao odeljak imaju svaki sopstveni
computemetod (store=True,readonly=False). Kad bi sva tri imala isti metod, eksplicitno prosleđena vrednost jednog polja poništila bi ostala. To se primećuje pre svega kada se čarobnjak kreira iz koda ili testova sa zadatim vrednostima. - Naziv odeljka sa količinom. Kod količine različite od 1 ona stoji u nazivu (2 × Merni komplet Standard, sa zarezom kao decimalnim separatorom), da bi se na štampanom primerku prepoznalo da su to dva seta, a ne jedan set sa udvostručenom količinom.
- Fiksna cena samo na redovima proizvoda.
prepare_sale_order_line_values()postavljahide_in_reportiprice_unitsamo ako red seta nije red odeljka ili beleške. - Standardni Odoo umesto sopstvene izrade. Režim štampe i skrivanje koriste postojeće kuke i polja Odoo 19. To čini ažuriranja podnošljivim: ako Odoo promeni šablon izveštaja, modul ostaje važeći dokle god metodi postoje.
Instalacija bez neželjenih sporednih efekata
Preduslovi: Odoo 19.0, sale_product_set (OCA/sale-workflow, grana 19.0) i product_set (OCA/product-attribute, grana 19.0). Sam modul zavisi od sale_management, sale_product_set i account.
Zamka auto_install kod OCA modula. Mnogi OCA repozitorijumi sadrže module sa auto_install. Čim su njihove zavisnosti prisutne, Odoo ih pri sledećoj instalaciji ili ažuriranju neupitno instalira zajedno. Ko zato stavi kompletan OCA repozitorijum u addons_path produktivne instance, možda dobije module koje niko nije hteo. Kod OCA/product-attribute to se, na primer, tiče modula purchase_product_template_tags. Naš postupak:
- Oba OCA repozitorijuma klonirati plitko (
git clone --depth 1 --branch 19.0). - U sopstvenom direktorijumu povezati simboličkim linkom samo dva potrebna modula i taj direktorijum uneti u
addons_path, a ne cele repozitorijume. - Instalirati na testnoj bazi i proveriti koji moduli pri tome dobijaju status instaliran.
- Tek tada instalirati produktivno, sa
--workers=0, kako poziv ne bi sa pokrenutom uslugom konkurisao za HTTP port.
odoo-bin -c /etc/odoo/odoo.conf -d <datenbank> -i sale_product_set_layout --stop-after-init
Nova polja i prikazi nalaze se u bazi podataka posle instalacije. Ako usluga radi u višeprocesnom režimu, radnici ponovo učitavaju izmenjeni registar preko signala baze podataka. Izmene Python fajlova modula postaju delotvorne tek posle restartovanja usluge.
Upotreba korak po korak
- Kreiranje seta: Prodaja → Proizvodi → Setovi proizvoda. Dati naziv setu, izabrati Umetni kao odeljak i Režim štampe, uneti proizvode sa količinama. Korekcione redove označiti sa Skriveno i Fiksna cena.
- U ponudi: kliknuti na Dodaj set, izabrati set i količinu. Naziv odeljka i režim štampe mogu se promeniti pre umetanja.
- Skrivanje pojedinačnih redova: u ponudi ili fakturi aktivirati kolonu Ne štampaj.
- Provera: otvoriti pregled ili PDF. Isti prikaz klijenti vide u portalu.
Testovi
Modul dolazi sa šest automatizovanih testova koje izvršavamo na testnoj bazi pre nego što bilo šta pređe u produkciju:
- Umetanje kao odeljak uključujući režim štampe i pododeljak
- Skriveni red nedostaje među redovima za štampu
- Režim Jedan red (
summary) - Umetanje bez odeljka, originalno ponašanje
- Faktura preuzima oznaku
hide_in_report, red nedostaje u_get_move_lines_to_report(), zbir odeljka ga i dalje sadrži - Faktura u režimu Samo ukupna cena ne prikazuje skriveni red u redovima odeljka, zbir odeljka ostaje potpun
odoo-bin -d <testdatenbank> -i sale_product_set_layout \
--test-enable --test-tags=/sale_product_set_layout --stop-after-init
Nemački prevod nalazi se u i18n/de.po.
Ograničenja i pravna napomena
- Samo izgled. Modul ne menja kako Odoo obračunava cene, popuste ili poreze. Menja samo ono što se štampa i prikazuje u portalu.
- Skriveni redovi su vidljivi u pozadinskom delu. Oznaka se odnosi na štampu i portal, a ne na prikaz na ekranu za zaposlene.
- Proveriti podatke na fakturi. Skriveni redovi ulaze u zbir, ali ne stoje na dokumentu. Da li je to usklađeno sa zahtevima za fakture u vašoj zemlji, na primer sa propisanim opisom isporučenih predmeta ili izvršenih usluga, treba da razjasnite sa vašim poreskim savetnikom pre upotrebe na fakturama. Na ponudama je skrivanje manje problematično. Članak nije pravni savet.
- Testirano za Odoo 19. Modul smo razvili i testirali za Odoo 19.0 Community. Koristi opcije odeljaka koje u ovom obliku postoje u Odoou 19. Za druge verzije ga nismo proveravali.
Česta pitanja
Čemu mi služi modul, ako Odoo 19 već ume odeljke?
Opcije odeljaka postoje u samom Odoou. Nedostajala je veza sa setom proizvoda: set je trebalo da se automatski umetne kao odeljak, sa režimom štampe zapisanim u setu. Bez modula se posle svakog umetanja red odeljka mora ručno kreirati i konfigurisati.
Po čemu se razlikuju „Sakrij cene“ i „Sakrij sastav“?
„Sakrij cene“ (collapse_prices) ostavlja redove, ali ne prikazuje iznose, samo zbir na odeljku. „Sakrij sastav“ (collapse_composition) potpuno sakriva redove, klijent vidi samo odeljak sa zbirom.
Da li skriveni red ulazi u zbir fakture?
Da. Skriveni redovi ostaju u zbiru, porezu i knjiženju. Oznaka se odnosi samo na prikaz na štampanom primerku i u portalu za klijente.
Mogu li režim štampe da promenim pri umetanju?
Da. Režim dolazi kao podrazumevana vrednost iz seta, a u čarobnjaku se može promeniti za konkretno umetanje. Sam set pri tom ostaje nepromenjen.
Šta se događa ako isključim Umetni kao odeljak?
Tada se čarobnjak ponaša kao u OCA modulu sale_product_set: redovi seta se umeću bez odeljka.
Da li modul neočekivano instalira druge module?
Sam modul ne. Kod OCA repozitorijuma ipak može doći do modula sa auto_install ako se celi repozitorijumi stave u addons_path. Zato povežite samo dva potrebna modula (vidi odeljak Instalacija).
Da li modul radi sa Odoo Enterprise?
Modul zavisi samo od Community modula (sale_management, account) i dva OCA modula. Koristimo ga na Odoo 19 Community. Na Enterprise ga nismo testirali.
Pod kojom licencom je modul?
Pod AGPL-3. Smete da ga koristite, prilagođavate i prosleđujete, sve dok izmene ostaju pod istom licencom. Greške i predlozi za poboljšanje dobrodošli su kao Issue u GitHub repozitorijumu .
Podrška kompanije Biricon IT Services
Brinemo o Odoo instalacijama za mala i srednja preduzeća: od uvođenja, preko prilagođavanja i migracija, do tekućeg rada. Ako želite da setove proizvoda, šablone ponuda ili izveštaje u Odoou 19 prilagodite svojim procesima, ili ako želite da proverite modul poput ovog i bezbedno ga unesete u svoju produktivnu instancu, rado ćemo vas podržati. Druge sopstvene razvoje pronaći ćete u našem blogu, na primer Spajanje nacrta faktura i Automatsko dodeljivanje bankovnih uplata fakturama.
Stanje na dan: 2. novembar 2026. Verzija modula 19.0.1.0.0. Primeri podataka na slikama su slobodno odabrani, iznosi su neto.