Ko u Odoou prodaje pakete, poput mjernog uređaja s priborom i montažom, radnog mjesta s hardverom i postavljanjem ili paketa održavanja s više usluga, u ponudi treba dvije stvari istovremeno: sastav mora biti naveden u narudžbi kako bi skladište, tehnička služba i služba za izdavanje računa znali šta se isporučuje. Međutim, na ispisu za kupca ne treba uvijek prikazati svaku pojedinačnu stavku s njenom cijenom.
OCA modul sale_product_set omogućava da se setovi proizvoda (sastavnice za prodaju) jednim klikom umetnu u ponudu. On ne određuje izgled ispisa. Za to smo razvili modul Sale Product Set Layout (sale_product_set_layout). Napisan je za Odoo 19 i besplatno je dostupan na GitHubu kao slobodni softver pod licencom AGPL-3:
github.com/Alex0176/odoo-sale-product-set-layout
Sadržaj članka
- Problem: setovi proizvoda bez kontrole nad izgledom ispisa
- Šta modul radi
- Detaljno o tri načina ispisa
- Skrivene stavke i fiksna cijena
- Tehnička implementacija
- Instalacija bez neželjenih posljedica
- Korištenje korak po korak
- Testovi
- Ograničenja i pravna napomena
- Česta pitanja
- Podrška kompanije Biricon IT Services
Problem: setovi proizvoda bez kontrole nad izgledom ispisa
Set proizvoda u Odoou je unaprijed pripremljena lista proizvoda s količinama. Umjesto da pojedinačno tražite deset artikala, u ponudi odaberete Dodaj set i odjednom dobijete sve stavke. To štedi vrijeme i sprečava izostavljanje stavki. Modul sale_product_set iz repozitorija OCA/sale-workflow radi upravo to; sami setovi dolaze iz modula product_set u repozitoriju OCA/product-attribute.
U praksi ostaju tri nedostatka:
- Nema jasnog grupisanja. Stavke seta u ponudi se pojavljuju kao nepovezane stavke. Nakon umetanja više se ne vidi koje stavke pripadaju zajedno, a ukupan iznos seta nigdje nije prikazan.
- Nema kontrole nad ispisom. Ponekad kupac treba vidjeti svaku stavku s cijenom, ponekad samo cijenu paketa, a ponekad samo jedan red. To treba odrediti za svaki set ili svakog kupca, bez ponovnog ručnog podešavanja u svakoj ponudi.
- Korekcije cijene su neugodne. Ako paket treba imati fiksnu cijenu koja odstupa od zbira cijena iz cjenovnika, potrebna je korektivna stavka. Ona spada u obračun, ali ne nužno i na papir za kupca.
Odoo 19 već sadrži elemente za uredno rješenje: odjeljke i pododjeljke među stavkama ponude s opcijama Sakrij cijene i Sakrij sastav (polja collapse_prices i collapse_composition). Modul povezuje set proizvoda s ovim standardnim opcijama umjesto da uvodi vlastiti format ispisa.
Šta modul radi
- Umetanje seta kao odjeljka. Čarobnjak Dodaj set kreira red odjeljka s nazivom seta, na primjer 2 × Messkit Standard, a ispod njega postavlja stavke seta. Odjeljci unutar seta postaju pododjeljci.
- Način ispisa za svaki set. Na setu se jednom definiše kako će se ispisivati. Pri umetanju se način ispisa u čarobnjaku može promijeniti za taj pojedinačni slučaj.
- Skrivanje stavki. Pojedinačne stavke mogu se označiti opcijom Ne ispisuj (na setu: Skriveno). Uključene su u ukupan iznos, ali se ne ispisuju niti prikazuju na portalu za kupce. Oznaka se prenosi s ponude na račun.
- Fiksna cijena po stavci seta. Stavka seta može imati fiksnu jediničnu cijenu koja zamjenjuje cijenu iz cjenovnika, na primjer za skrivenu korekciju cijene.
Bez modula (samo sale_product_set) | Uz sale_product_set_layout |
|---|---|
| Stavke seta kao nepovezane stavke | Red odjeljka s nazivom seta i količinom u nazivu, sa stavkama ispod |
| Odjeljci u setu ostaju odjeljci i narušavaju strukturu | Odjeljci u setu postaju pododjeljci (line_subsection) |
| Izgled ispisa uvijek je isti | Način ispisa za svaki set, uz mogućnost promjene pri umetanju |
| Korekcija cijene vidljiva je na ponudi i računu | Stavka se može sakriti, ali ostaje uključena u ukupan iznos |
| Cijena isključivo iz cjenovnika | Opcionalna fiksna cijena po stavci seta |
| Oblikovanje se primjenjuje samo na ponudu | Oblikovanje i skrivanje primjenjuju se na ponudu, narudžbu, račun i portal za kupce |
Detaljno o tri načina ispisa
Način ispisa je izborno polje print_mode na setu proizvoda. Pri umetanju pretvara se u postavke dva standardna prekidača na redu odjeljka. Modul za to koristi jedno jednostavno i čitljivo mapiranje:
# Način ispisa -> (collapse_prices, collapse_composition) reda odjeljka
PRINT_MODE_FLAGS = {
"detailed": (False, False),
"total_only": (True, False),
"summary": (False, True),
}
Način (print_mode) | Prikaz u setu | Standardna opcija u Odoou | Izgled ispisa |
|---|---|---|---|
detailed | Svaka stavka s cijenom | nijedna | Odjeljak, sve stavke s iznosima |
total_only | Stavke bez cijena, samo ukupan iznos seta | collapse_prices (Sakrij cijene) | Odjeljak s ukupnim iznosom, stavke samo s nazivom i količinom |
summary | Samo jedan red s ukupnim iznosom seta | collapse_composition (Sakrij sastav) | Samo red odjeljka s ukupnim iznosom |
Budući da modul koristi standardne opcije Odooa 19, a ne vlastiti format ispisa, ponuda, potvrda narudžbe, račun i portal za kupce rade bez prilagođavanja predložaka izvještaja. Isto ponašanje dostupno je i onima čiji vlastiti predlošci izvještaja podržavaju opcije odjeljaka.
Skrivene stavke i fiksna cijena
Čest slučaj: paket ima cijenu nižu od zbira pojedinačnih cijena. Umjesto mijenjanja pojedinačnih cijena koristi se korektivna stavka s fiksnom cijenom (na primjer −50,00 € po setu), koja se zatim sakrije. U administracijskom dijelu obračun je jasan, a na ispisu je prikazana cijena paketa.
Važno za razumijevanje: oznaka hide_in_report ne mijenja obračun. Količinu, cijenu, popust, porez, ukupne iznose i knjiženja i dalje obrađuje standardni Odoo. Stavka se samo izostavlja iz ispisa i portala.
- Na setu proizvoda: stavka seta s oznakom Skriveno i opcionalno Fiksna cijena uz Jediničnu cijenu.
- Na stavkama ponude i računa: kolona Ne ispisuj (
hide_in_report), dostupna i za obične stavke bez seta. - Prenošenje: pri kreiranju računa iz narudžbe oznaka se prenosi na stavku računa. Pri kopiranju ponude ostaje sačuvana.
Tehnička implementacija
Modul je namjerno malog opsega: proširuje postojeće modele i redefiniše samo mjesta na kojima Odoo odlučuje koje se stavke ispisuju i kako se set umeće. Nema novih predložaka izvještaja, novih modela ni zahvata putem SQL-a.
Prošireni modeli i polja
| Model | Dopuna |
|---|---|
product.set | Polja insert_as_section (logičko polje, podrazumijevano uključeno) i print_mode (izborno, obavezno polje, podrazumijevana vrijednost detailed) |
product.set.line | Polja hide_in_report, fixed_price, price_unit; prepare_sale_order_line_values() prenosi ih na stavku ponude |
sale.product.set.wizard | Polja insert_as_section, section_name, print_mode; _prepare_order_lines() kreira red odjeljka |
sale.order / sale.order.line | Polje hide_in_report (uz copy=True); _get_order_lines_to_report() preskače skrivene stavke; _prepare_invoice_line() prenosi oznaku |
account.move / account.move.line | Polje hide_in_report; _get_move_lines_to_report(), _get_detailed_lines() i _get_subsection_lines() filtriraju skrivene stavke; _get_aml_vals() dodaje oznaku u podatke izvještaja |
Skrivanje u ponudi
Odoo 19 određuje stavke ponude za ispis u metodi _get_order_lines_to_report(). Modul tu dodaje filter. Nije potrebno mijenjati predložak izvještaja: i predložak izvještaja ponude (sale/report/ir_actions_report_templates.xml) i predložak portala (sale/views/sale_portal_templates.xml) pozivaju ovu metodu:
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
)
Prenošenje na račun
Pri kreiranju stavke računa iz stavke ponude (_prepare_invoice_line()) oznaka se kopira. Na strani računa u Odoou 19 postoji više puteva kojima stavke ulaze u izvještaj: glavna lista, stavke odjeljka i stavke pododjeljka. Zato modul filtrira na više mjesta (_get_move_lines_to_report() na dokumentu, _get_detailed_lines() i _get_subsection_lines() na stavci), jer bi se u suprotnom skrivena stavka mogla ponovo pojaviti nekim od drugih 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: odjeljak umjesto nepovezanih stavki
Čarobnjak sale.product.set.wizard iz modula sale_product_set kreira stavke ponude u metodi _prepare_order_lines(). Modul redefiniše ovu metodu. Ako je opcija Umetni kao odjeljak isključena, jednostavno poziva izvornu metodu, pa ponašanje ostaje isto kao u OCA modulu. U suprotnom prvo nastaje red odjeljka s dva standardna prekidača, a zatim slijede stavke seta. Odjeljci unutar seta postaju pododjeljci kako ne bi narušili 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
- Odvojene metode izračuna u čarobnjaku. Naziv odjeljka, način ispisa i opcija Umetni kao odjeljak imaju zasebne
computemetode (store=True,readonly=False). Kada bi sva tri polja koristila istu metodu, izričito proslijeđena vrijednost jednog polja resetovala bi ostala. To posebno dolazi do izražaja kada se čarobnjak kreira iz koda ili testova uz zadane vrijednosti. - Naziv odjeljka s količinom. Ako količina nije jednaka 1, navodi se u nazivu (2 × Messkit Standard, sa zarezom kao decimalnim separatorom), kako bi se na ispisu vidjelo da se radi o dva seta, a ne o jednom setu s dvostrukom količinom.
- Fiksna cijena samo na stavkama proizvoda.
prepare_sale_order_line_values()postavljahide_in_reportiprice_unitsamo ako stavka seta nije red odjeljka ili napomene. - Standardni Odoo umjesto vlastitog rješenja. Način ispisa i skrivanje koriste postojeće tačke proširenja i polja Odooa 19. To olakšava nadogradnje: ako Odoo promijeni predložak izvještaja, modul ostaje funkcionalan dok god postoje odgovarajuće metode.
Instalacija bez neželjenih posljedica
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 modula sale_management, sale_product_set i account.
Zamka opcije auto_install kod OCA modula. Mnogi OCA repozitoriji sadrže module s opcijom auto_install. Čim su njihove zavisnosti dostupne, Odoo ih pri sljedećoj instalaciji ili nadogradnji automatski instalira bez pitanja. Ako zbog toga cijeli OCA repozitorij dodate u addons_path produkcijske instance, možete dobiti module koje niko nije želio. U repozitoriju OCA/product-attribute to se, na primjer, odnosi na purchase_product_template_tags. Naš postupak:
- Kreirajte plitke klonove oba OCA repozitorija (
git clone --depth 1 --branch 19.0). - U zasebnom direktoriju napravite simboličke linkove samo na dva potrebna modula i dodajte taj direktorij u
addons_path, a ne cijele repozitorije. - Instalirajte na testnoj bazi podataka i provjerite koji moduli pri tome dobiju status instalirano.
- Tek zatim instalirajte u produkciji, uz
--workers=0, kako se pokrenuta naredba ne bi nadmetala s aktivnim servisom 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 nakon instalacije. Ako servis radi u više procesa, radni procesi učitavaju izmijenjeni registar putem signala baze podataka. Promjene u Python datotekama modula stupaju na snagu tek nakon ponovnog pokretanja servisa.
Korištenje korak po korak
- Kreiranje seta: Prodaja → Proizvodi → Setovi proizvoda. Unesite naziv seta, odaberite Umetni kao odjeljak i Način ispisa te unesite proizvode s količinama. Korektivne stavke označite opcijama Skriveno i Fiksna cijena.
- U ponudi: kliknite na Dodaj set, odaberite set i količinu. Naziv odjeljka i način ispisa mogu se promijeniti prije umetanja.
- Skrivanje pojedinačnih stavki: u ponudi ili na računu uključite opciju u koloni Ne ispisuj.
- Provjera: otvorite pregled ili PDF. Kupci vide isti prikaz na portalu.
Testovi
Modul sadrži šest automatizovanih testova koje izvršavamo na testnoj bazi podataka prije puštanja u produkciju:
- Umetanje kao odjeljak, uključujući način ispisa i pododjeljak
- Skrivena stavka nije među stavkama za ispis
- Način Jedan red (
summary) - Umetanje bez odjeljka, izvorno ponašanje
- Račun preuzima oznaku
hide_in_report, stavka se izostavlja iz_get_move_lines_to_report(), ali ostaje uključena u ukupan iznos odjeljka - Račun u načinu Samo ukupna cijena ne prikazuje skrivenu stavku među stavkama odjeljka, a ukupan iznos odjeljka ostaje potpun
odoo-bin -d <testdatenbank> -i sale_product_set_layout \
--test-enable --test-tags=/sale_product_set_layout --stop-after-init
Njemački prijevod nalazi se u datoteci i18n/de.po.
Ograničenja i pravna napomena
- Samo oblikovanje. Modul ne mijenja način na koji Odoo obračunava cijene, popuste ili poreze. Mijenja samo ono što se ispisuje i prikazuje na portalu.
- Skriveni redovi vidljivi su u administracijskom sučelju. Oznaka se odnosi na ispis i portal, a ne na prikaz koji vide zaposlenici.
- Provjerite podatke na računu. Skriveni redovi ulaze u ukupan iznos, ali se ne prikazuju na dokumentu. Je li to u skladu sa zahtjevima za račune u vašoj zemlji, primjerice s obaveznim opisom isporučene robe ili pruženih usluga, trebate razjasniti sa svojim poreznim savjetnikom prije upotrebe na računima. Skrivanje je manje problematično na ponudama. Ovaj članak ne predstavlja pravni savjet.
- Testirano za Odoo 19. Modul smo razvili i testirali za Odoo 19.0 Community. Koristi opcije odjeljaka koje su u ovom obliku dostupne u Odoo 19. Nismo ga provjeravali za druge verzije.
Česta pitanja
Zašto mi treba ovaj modul ako Odoo 19 već podržava odjeljke?
Opcije odjeljaka postoje u samom Odoo. Nedostajala je povezanost sa setom proizvoda: set se treba automatski umetnuti kao odjeljak, uz način ispisa podešen u setu. Bez ovog modula nakon svakog umetanja morate ručno kreirati i podesiti red odjeljka.
Koja je razlika između opcija „Sakrij cijene“ i „Sakrij sastav“?
Opcija „Sakrij cijene“ (collapse_prices) zadržava redove, ali ne prikazuje njihove iznose, nego samo ukupan iznos odjeljka. Opcija „Sakrij sastav“ (collapse_composition) potpuno skriva redove pa kupac vidi samo odjeljak s ukupnim iznosom.
Ulazi li skriveni red u ukupan iznos računa?
Da. Skriveni redovi i dalje ulaze u ukupan iznos, obračun poreza i knjiženje. Oznaka utiče samo na prikaz na ispisu i u korisničkom portalu.
Mogu li promijeniti način ispisa pri umetanju?
Da. Zadani način ispisa preuzima se iz seta, a u čarobnjaku se može promijeniti za pojedinačno umetanje. Sam set pritom ostaje neizmijenjen.
Šta se dešava ako isključim opciju Umetni kao odjeljak?
Tada čarobnjak radi kao u OCA modulu sale_product_set: redovi seta umeću se bez odjeljka.
Instalira li modul neočekivano dodatne module?
Sam modul ne instalira. Međutim, kod OCA repozitorija može doći do instaliranja modula s oznakom auto_install ako cijele repozitorije dodate u addons_path. Zato povežite samo dva potrebna modula (pogledajte odjeljak Instalacija).
Radi li modul uz Odoo Enterprise?
Modul zavisi samo od Community modula (sale_management, account) i dva OCA modula. Koristimo ga u Odoo 19 Community. Nismo ga testirali na Enterprise izdanju.
Pod kojom je licencom modul dostupan?
Pod licencom AGPL-3. Smijete ga koristiti, prilagođavati i distribuirati dok god izmjene ostaju pod istom licencom. Greške i prijedloge poboljšanja možete prijaviti kao Issue u GitHub repozitoriju .
Podrška kompanije Biricon IT Services
Pružamo podršku za Odoo instalacije malih i srednjih preduzeća: od uvođenja, prilagodbi i migracija do svakodnevnog rada. Ako želite prilagoditi setove proizvoda, predloške ponuda ili izvještaje u Odoo 19 svojim poslovnim procesima ili provjeriti modul poput ovog i sigurno ga uvesti u produkcijsko okruženje, rado ćemo vam pomoći. Više naših vlastitih rješenja pronaći ćete na blogu, naprimjer Spajanje nacrta računa i Automatsko povezivanje bankovnih uplata s računima.
Stanje na dan: 2. novembra 2026. Verzija modula 19.0.1.0.0. Primjeri podataka na slikama proizvoljno su odabrani, iznosi su bez poreza.