Preskoči na sadržaj

Odoo 19 Community: setovi proizvoda u ponudi kao odjeljak – naš open-source modul Sale Product Set Layout

2. novembar 2026 | Odoo 19 Community | Vlastiti razvoj
2. novembar 2026. by
Odoo 19 Community: setovi proizvoda u ponudi kao odjeljak – naš open-source modul Sale Product Set Layout

Odoo 19 modul Sale Product Set Layout: setovi proizvoda kao odjeljak u ponudi s načinom štampe, skrivenim stavkama i fiksnom cijenom

Ko u Odoou prodaje pakete, na primjer mjerni uređaj s priborom i montažom, radno mjesto s hardverom i postavljanjem ili paket održavanja od više usluga, treba u ponudi istovremeno dvije stvari: Sastav mora stajati u narudžbi, kako bi skladište, tehnika i fakturisanje znali šta se isporučuje. Na štampanom primjerku za kupca pak ne mora u svakom slučaju biti prikazana svaka pojedinačna stavka sa svakom pojedinačnom cijenom.

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 licencom AGPL-3:

github.com/Alex0176/odoo-sale-product-set-layout

Problem: setovi proizvoda bez utjecaja na izgled štampe

Set proizvoda je u Odoou unaprijed pripremljena lista proizvoda s količinama. Umjesto da se deset artikala traži pojedinačno, u ponudi se odabere Dodaj set i odmah se dobiju sve stavke. To štedi vrijeme i sprječava zaboravljene stavke. Modul sale_product_set iz repozitorija OCA/sale-workflow radi upravo to; sami setovi potiču iz product_set u repozitoriju OCA/product-attribute.

U praksi ostaju tri praznine:

  • Nema prepoznatljivog grupisanja. Stavke seta završavaju kao slobodne pozicije u ponudi. Nakon umetanja više se ne vidi koje stavke pripadaju zajedno, a ukupan iznos seta nigdje ne stoji.
  • Nema utjecaja na štampu. Ponekad kupac treba vidjeti svaku poziciju s cijenom, ponekad samo cijenu paketa, a ponekad samo jednu jedinu stavku. To je odluka po setu ili po kupcu, a ne nešto što se za svaku ponudu iznova rješava ručno.
  • 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 donosi gradivne elemente da se to čisto riješi: odjeljci i pododjeljci u stavkama ponude s opcijama Sakrij cijene i Sakrij sastav (polja collapse_prices i collapse_composition). Modul povezuje set proizvoda s tim standardnim opcijama umjesto da izmišlja vlastiti format štampe.

Šta modul radi

  1. Umetanje seta kao odjeljka. Čarobnjak Dodaj set kreira stavku odjeljka s nazivom seta, na primjer 2 × Messkit Standard, i postavlja stavke seta ispod nje. Odjeljci unutar seta postaju pododjeljci.
  2. Način štampe po setu. U setu se jednom određuje kako će se štampati. Pri umetanju se način može u čarobnjaku promijeniti za taj jedan slučaj.
  3. Skrivanje stavki. Pojedine stavke mogu se označiti kao Ne štampaj (u setu: Skriveno). One se računaju u zbir, ali se ne štampaju niti prikazuju u portalu za kupce. Oznaka se prenosi s ponude na račun.
  4. Fiksna cijena po stavci seta. Stavka seta može nositi fiksnu jediničnu cijenu koja zamjenjuje cijenu iz cjenovnika, na primjer za skrivenu korekciju cijene.
Bez modula (samo sale_product_set)Sa sale_product_set_layout
Stavke seta kao slobodne pozicijeStavka odjeljka s nazivom seta, količinom u nazivu i stavkama ispod
Odjeljci u setu ostaju odjeljci i razbijaju strukturuOdjeljci u setu postaju pododjeljci (line_subsection)
Izgled štampe uvijek istiNačin štampe po setu, može se promijeniti pri umetanju
Korekcija cijene vidljiva na ponudi i računuStavka se može sakriti, ali se računa u zbir
Cijena samo iz cjenovnikaOpcionalno fiksna cijena po stavci seta
Izgled završava na ponudiIzgled i skrivanje vrijede za ponudu, narudžbu, račun i portal za kupce

Tri načina štampe detaljno

Način štampe je polje za odabir print_mode na setu proizvoda. Pri umetanju se prevodi u dva standardna prekidača stavke odjeljka. Za to u modulu postoji jedno jedino, lako čitljivo preslikavanje:

# Druckmodus -> (collapse_prices, collapse_composition) der Abschnittszeile
PRINT_MODE_FLAGS = {
    "detailed":   (False, False),
    "total_only": (True,  False),
    "summary":    (False, True),
}

Tri izgleda štampe istog seta proizvoda: svaka stavka s cijenom, samo ukupna cijena, jedna jedina stavka

Način (print_mode)Prikaz u setuStandardna opcija u OdoouIzgled štampe
detailedSvaka stavka s cijenomnijednaOdjeljak, sve stavke s iznosom
total_onlyStavke bez cijena, samo zbir setacollapse_prices (Sakrij cijene)Odjeljak sa zbirom, stavke samo s nazivom i količinom
summarySamo jedna stavka sa zbirom setacollapse_composition (Sakrij sastav)Samo stavka odjeljka sa zbirom

Budući da modul koristi standardne opcije Odoo 19, a ne vlastiti format štampe, ponuda, potvrda narudžbe, račun i portal za kupce rade bez prilagođenih predložaka izvještaja. Ko ima vlastite predloške izvještaja koji uvažavaju opcije odjeljaka, dobiva isto ponašanje.

Skrivene stavke i fiksna cijena

Čest slučaj: paket ima cijenu paketa koja je ispod zbira pojedinačnih cijena. Umjesto da se pojedinačne cijene krive, uzima se korektivna stavka s fiksnom cijenom (na primjer −50,00 € po setu) i skriva se. U backendu je račun razumljiv, a na štampanom primjerku stoji cijena paketa.

Korekcija cijene u backendu vidljiva i označena, u štampi ponude, PDF-u, računa i portala nije vidljiva, zbir je identičan

Važno za razumijevanje: oznaka hide_in_report ne mijenja ništa u obračunu. Količina, cijena, popust, porez, zbirovi i knjiženja nastaju nepromijenjeno putem standardnog Odoa. Stavka samo nedostaje u štampi i u portalu.

  • Na setu proizvoda: stavka seta s Skriveno i opcionalno Fiksna cijena zajedno s Jediničnom cijenom.
  • Na stavkama ponude i računa: kolona Ne štampaj (hide_in_report), 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 ona se zadržava.

Tehnička realizacija

Modul je namjerno mali: proširuje postojeće modele i nadjačava samo ona mjesta na kojima Odoo odlučuje koje se stavke štampaju i kako se set umeće. Nema novih predložaka izvještaja, novih modela ni SQL zahvata.

Tok podataka: set proizvoda, čarobnjak Dodaj set, stavke ponude, stavke računa, PDF i portal za kupce

Prošireni modeli i polja

ModelDopuna
product.setPolja insert_as_section (Boolean, standardno uključeno) i print_mode (izbor, obavezno polje, standardno detailed)
product.set.linePolja hide_in_report, fixed_price, price_unit; prepare_sale_order_line_values() ih prosljeđuje stavci ponude
sale.product.set.wizardPolja insert_as_section, section_name, print_mode; _prepare_order_lines() gradi stavku odjeljka
sale.order / sale.order.linePolje hide_in_report (sa copy=True); _get_order_lines_to_report() preskače skrivene stavke; _prepare_invoice_line() prosljeđuje oznaku
account.move / account.move.linePolje hide_in_report; _get_move_lines_to_report(), _get_detailed_lines() i _get_subsection_lines() filtriraju skrivene stavke; _get_aml_vals() upisuje oznaku u podatke izvještaja

Skrivanje u ponudi

Odoo 19 određuje stavke ponude za štampu u _get_order_lines_to_report(). Modul tamo dodaje filter. Zahvat u predložak izvještaja nije potreban: 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 Odoo 19 postoji više putova kojima stavke dospijevaju 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), inače bi se 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 slobodnih stavki

Čarobnjak sale.product.set.wizard iz sale_product_set kreira stavke ponude u _prepare_order_lines(). Modul nadjačava ovu metodu. Ako je Umetni kao odjeljak isključeno, jednostavno poziva izvornu metodu i ponašanje ostaje kao u OCA modulu. U suprotnom se prvo kreira stavka odjeljka s dva standardna prekidača, a zatim slijede stavke seta. Odjeljci unutar seta postaju pododjeljci kako ne bi razbijali 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 štampe i Umetni kao odjeljak imaju svaki svoju compute metodu (store=True, readonly=False). Kad bi sva tri dijelila istu metodu, eksplicitno proslijeđena vrijednost jednog polja poništila bi ostala. To se najviše primijeti kad se čarobnjak kreira iz koda ili testova s unaprijed zadanim vrijednostima.
  • Naziv odjeljka s količinom. Pri količini različitoj od 1 ona stoji u nazivu (2 × Messkit Standard, sa zarezom kao decimalnim separatorom), kako bi se u štampi prepoznalo 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() postavlja hide_in_report i price_unit samo ako stavka seta nije stavka odjeljka ili bilješke.
  • Standardni Odoo umjesto vlastite izrade. Način štampe i skrivanje koriste postojeće hookove i polja Odoo 19. To čini ažuriranja podnošljivim: ako Odoo promijeni predložak izvještaja, modul ostaje važeći sve dok metode postoje.

Instalacija bez neželjenih nuspojava

Preduvjeti: 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 repozitoriji sadrže module s auto_install. Čim su njihove zavisnosti prisutne, Odoo ih pri sljedećoj instalaciji ili ažuriranju neupitano instalira zajedno s ostalim. Ko zato cijeli OCA repozitorij stavi u addons_path produktivne instance, možda dobije module koje niko nije htio. Kod OCA/product-attribute to se, na primjer, odnosi na purchase_product_template_tags. Naš postupak:

  1. Oba OCA repozitorija klonirati plitko (git clone --depth 1 --branch 19.0).
  2. U zasebnom direktoriju povezati simboličkim linkom samo dva potrebna modula i taj direktorij uključiti u addons_path, a ne cijele repozitorije.
  3. Instalirati na testnu bazu podataka i provjeriti koji moduli pritom dobiju status instaliran.
  4. Tek tada instalirati produktivno, s --workers=0, kako poziv ne bi sa pokrenutom uslugom konkurirao 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 usluga radi u višeprocesnom režimu, workeri ponovo učitavaju promijenjeni registar putem signala baze podataka. Izmjene Python fajlova modula postaju djelotvorne tek nakon ponovnog pokretanja usluge.

Rukovanje korak po korak

  1. Kreiranje seta: Prodaja → Proizvodi → Setovi proizvoda. Dati ime setu, odabrati Umetni kao odjeljak i Način štampe, unijeti proizvode s količinama. Korektivne stavke označiti sa Skriveno i Fiksna cijena.
  2. U ponudi: kliknuti na Dodaj set, odabrati set i količinu. Naziv odjeljka i način štampe mogu se promijeniti prije umetanja.
  3. Skrivanje pojedinih stavki: u ponudi ili računu aktivirati kolonu Ne štampaj.
  4. Provjera: otvoriti pregled ili PDF. Isti prikaz kupci vide u portalu.

Testovi

Modul sadrži šest automatizovanih testova koje izvršavamo na testnoj bazi podataka prije nego što bilo šta ide u produkciju:

  • Umetanje kao odjeljak uključujući način štampe i pododjeljak
  • Skrivena stavka nedostaje među stavkama za štampu
  • Način Jedna stavka (summary)
  • Umetanje bez odjeljka, izvorno ponašanje
  • Račun preuzima oznaku hide_in_report, stavka nedostaje u _get_move_lines_to_report(), zbir odjeljka ih i dalje uključuje
  • Račun u načinu Samo ukupna cijena ne prikazuje skrivenu stavku među stavkama odjeljka, zbir 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 prevod nalazi se u i18n/de.po.

Ograničenja i pravna napomena

  • Samo izgled. Modul ne mijenja način na koji Odoo računa cijene, popuste ili poreze. Mijenja samo ono što se štampa i prikazuje u portalu.
  • Skrivene stavke su vidljive u backendu. Oznaka se odnosi na štampu i portal, a ne na prikaz na ekranu za zaposlene.
  • Provjerite podatke na računu. Skrivene stavke ulaze u zbir, ali ne stoje na dokumentu. Je li to usklađeno sa zahtjevima za račune u vašoj zemlji, na primjer s propisanim opisom isporučenih predmeta ili izvršenih usluga, trebali biste prije upotrebe na računima razjasniti sa svojim poreznim savjetnikom. Na ponudama je skrivanje manje problematično. Članak nije pravni savjet.
  • Testirano za Odoo 19. Modul smo razvili i testirali za Odoo 19.0 Community. Koristi opcije odjeljaka koje u ovom obliku postoje u Odoo 19. Za druge verzije ga nismo provjeravali.

Česta pitanja

Čemu mi služi modul ako Odoo 19 već poznaje odjeljke?

Opcije odjeljaka postoje u samom Odoou. Nedostajala je veza sa setom proizvoda: set bi se trebao automatski umetati kao odjeljak, s načinom štampe pohranjenim u setu. Bez modula se nakon svakog umetanja stavka odjeljka mora ručno kreirati i konfigurisati.

Po čemu se razlikuju „Sakrij cijene“ i „Sakrij sastav“?

„Sakrij cijene“ (collapse_prices) ostavlja stavke, ali ne prikazuje iznose, samo zbir na odjeljku. „Sakrij sastav“ (collapse_composition) potpuno skriva stavke, kupac vidi samo odjeljak sa zbirom.

Računa li se skrivena stavka u zbir računa?

Da. Skrivene stavke ostaju u zbiru, porezu i knjiženju. Oznaka se odnosi samo na prikaz na štampanom primjerku i u portalu za kupce.

Mogu li način štampe još promijeniti pri umetanju?

Da. Način dolazi kao zadana vrijednost iz seta, a u čarobnjaku se može promijeniti za dotično umetanje. Sam set pritom ostaje nepromijenjen.

Šta se događa ako isključim Umetni kao odjeljak?

Tada se čarobnjak ponaša kao u OCA modulu sale_product_set: stavke seta se umeću bez odjeljka.

Instalira li modul neočekivano dodatne module?

Sam modul ne. No kod OCA repozitorija može doći do auto_install modula ako se cijeli repozitoriji stave u addons_path. Zato povežite samo dva potrebna modula (vidi odjeljak Instalacija).

Radi li modul s Odoo Enterprise?

Modul zavisi samo od Community modula (sale_management, account) i od dva OCA modula. Koristimo ga na Odoo 19 Community. Na Enterprise ga nismo testirali.

Pod kojom licencom je modul?

Pod AGPL-3. Smijete ga koristiti, prilagođavati i dalje distribuirati, sve dok izmjene ostaju pod istom licencom. Greške i prijedlozi poboljšanja dobrodošli su kao issue u GitHub repozitoriju .

Podrška Biricon IT Services

Brinemo o Odoo instalacijama za mala i srednja preduzeća: od uvođenja, preko prilagodbi i migracija, do tekućeg rada. Ako želite da setove proizvoda, predloške ponuda ili izvještaje u Odoo 19 prilagodite svojim procesima, ili ako želite provjeriti modul poput ovog i sigurno ga postaviti u svoju produktivnu instancu, rado ćemo vas podržati. Daljnje vlastite razvojne projekte pronaći ćete u našem blogu, na primjer Spajanje nacrta računa i Automatsko dodjeljivanje bankovnih uplata računima.

Obratite nam se sada

Stanje na dan: 2. novembra 2026. Verzija modula 19.0.1.0.0. Primjeri podataka na slikama su proizvoljno odabrani, iznosi su neto.