Merge feature/kw-kalkulacija-prodajna: dvosmerna marža↔prodajna + status PDV obveznika
This commit is contained in:
@@ -31,6 +31,7 @@ type PodaciFormeNabavke struct {
|
|||||||
Dobavljaci []model.Dobavljac
|
Dobavljaci []model.Dobavljac
|
||||||
Kategorije []model.Kategorija // za dropdown u modalu novog artikla
|
Kategorije []model.Kategorija // za dropdown u modalu novog artikla
|
||||||
Marza string // podrazumevana marža (%) za kalkulaciju
|
Marza string // podrazumevana marža (%) za kalkulaciju
|
||||||
|
PdvObveznik bool // da li firma obračunava PDV (utiče na prodajnu cenu u kalkulaciji)
|
||||||
Greska string
|
Greska string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +128,7 @@ func (h *Handler) NovaNabavka(w http.ResponseWriter, r *http.Request) {
|
|||||||
Dobavljaci: dobavljaci,
|
Dobavljaci: dobavljaci,
|
||||||
Kategorije: kategorije,
|
Kategorije: kategorije,
|
||||||
Marza: vrednostIliDefault(podesavanja, "kalkulacija_marza", "20"),
|
Marza: vrednostIliDefault(podesavanja, "kalkulacija_marza", "20"),
|
||||||
|
PdvObveznik: h.modulUkljucen(r.Context(), "pdv"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,6 +159,7 @@ func (h *Handler) SacuvajNabavku(w http.ResponseWriter, r *http.Request) {
|
|||||||
Dobavljaci: dobavljaci,
|
Dobavljaci: dobavljaci,
|
||||||
Kategorije: kategorije,
|
Kategorije: kategorije,
|
||||||
Marza: vrednostIliDefault(podesavanja, "kalkulacija_marza", "20"),
|
Marza: vrednostIliDefault(podesavanja, "kalkulacija_marza", "20"),
|
||||||
|
PdvObveznik: h.modulUkljucen(r.Context(), "pdv"),
|
||||||
Greska: greska,
|
Greska: greska,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|||||||
+15
-1
@@ -191,6 +191,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
marzaDefault: 0,
|
marzaDefault: 0,
|
||||||
troskovi: [], // zavisni troškovi {naziv, iznos}
|
troskovi: [], // zavisni troškovi {naziv, iznos}
|
||||||
metodRaspodele: 'vrednost', // 'vrednost' ili 'kolicina'
|
metodRaspodele: 'vrednost', // 'vrednost' ili 'kolicina'
|
||||||
|
pdvObveznik: true, // da li firma obračunava PDV (utiče na prodajnu cenu)
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
modal: false,
|
modal: false,
|
||||||
modalUcitavanje: false,
|
modalUcitavanje: false,
|
||||||
@@ -216,6 +217,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
init() {
|
init() {
|
||||||
this.artikliOpcije = window._ntechArtikli || []
|
this.artikliOpcije = window._ntechArtikli || []
|
||||||
this.marzaDefault = parseFloat(window._ntechMarza) || 0
|
this.marzaDefault = parseFloat(window._ntechMarza) || 0
|
||||||
|
this.pdvObveznik = window._ntechPdvObveznik === true
|
||||||
this.stavke.forEach(s => { s.marza = this.marzaDefault })
|
this.stavke.forEach(s => { s.marza = this.marzaDefault })
|
||||||
this.isMobile = window.matchMedia('(max-width: 768px)').matches
|
this.isMobile = window.matchMedia('(max-width: 768px)').matches
|
||||||
window.matchMedia('(max-width: 768px)').addEventListener('change', e => {
|
window.matchMedia('(max-width: 768px)').addEventListener('change', e => {
|
||||||
@@ -226,8 +228,10 @@ document.addEventListener('alpine:init', () => {
|
|||||||
this.stavke.push({artikal_id: '', kolicina: 1, cena: 0, marza: this.marzaDefault, prodajna: 0})
|
this.stavke.push({artikal_id: '', kolicina: 1, cena: 0, marza: this.marzaDefault, prodajna: 0})
|
||||||
this.preracunajSve()
|
this.preracunajSve()
|
||||||
},
|
},
|
||||||
// PDV stopa izabranog artikla (iz JSON liste) — za obračun prodajne cene
|
// PDV stopa izabranog artikla (iz JSON liste) — za obračun prodajne cene.
|
||||||
|
// Ako firma nije PDV obveznik, PDV se ne dodaje na prodajnu cenu (stopa = 0).
|
||||||
pdvStopa(artikalId) {
|
pdvStopa(artikalId) {
|
||||||
|
if (!this.pdvObveznik) return 0
|
||||||
const a = this.artikliOpcije.find(x => String(x.id) === String(artikalId))
|
const a = this.artikliOpcije.find(x => String(x.id) === String(artikalId))
|
||||||
return a ? (parseFloat(a.pdv_stopa) || 0) : 0
|
return a ? (parseFloat(a.pdv_stopa) || 0) : 0
|
||||||
},
|
},
|
||||||
@@ -270,6 +274,16 @@ document.addEventListener('alpine:init', () => {
|
|||||||
const pdv = this.pdvStopa(s.artikal_id)
|
const pdv = this.pdvStopa(s.artikal_id)
|
||||||
s.prodajna = Math.round(nabavna * (1 + marza / 100) * (1 + pdv / 100) * 100) / 100
|
s.prodajna = Math.round(nabavna * (1 + marza / 100) * (1 + pdv / 100) * 100) / 100
|
||||||
},
|
},
|
||||||
|
// obrnuti smer: iz ručno unete prodajne cene izvedi maržu (%)
|
||||||
|
// marža = (prodajna / (nabavna × (1 + pdv/100)) − 1) × 100
|
||||||
|
izracunajMarzu(s) {
|
||||||
|
const nabavna = this.kalkNabavna(s)
|
||||||
|
const pdv = this.pdvStopa(s.artikal_id)
|
||||||
|
const osnovica = nabavna * (1 + pdv / 100)
|
||||||
|
if (osnovica <= 0) return // bez nabavne cene marža se ne može izvesti
|
||||||
|
const prodajna = parseFloat(s.prodajna) || 0
|
||||||
|
s.marza = Math.round(((prodajna / osnovica) - 1) * 100 * 100) / 100
|
||||||
|
},
|
||||||
// raspodela zavisi od svih stavki — promena troška/metoda/količine/cene preračunava sve
|
// raspodela zavisi od svih stavki — promena troška/metoda/količine/cene preračunava sve
|
||||||
preracunajSve() {
|
preracunajSve() {
|
||||||
this.stavke.forEach(s => this.izracunajProdajnu(s))
|
this.stavke.forEach(s => this.izracunajProdajnu(s))
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
{{define "sadrzaj"}}
|
{{define "sadrzaj"}}
|
||||||
|
|
||||||
<!-- lista artikala kao JSON — bezbedno serijalizovana na serveru -->
|
<!-- lista artikala kao JSON — bezbedno serijalizovana na serveru -->
|
||||||
<script>var _ntechArtikli = {{.ArtikliJSON}}; var _ntechMarza = {{.Marza}};</script>
|
<script>var _ntechArtikli = {{.ArtikliJSON}}; var _ntechMarza = {{.Marza}}; var _ntechPdvObveznik = {{.PdvObveznik}};</script>
|
||||||
|
|
||||||
<div style="width:100%;" x-data="nabavkaForma">
|
<div style="width:100%;" x-data="nabavkaForma">
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
<th style="padding:8px 10px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Artikal</th>
|
<th style="padding:8px 10px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Artikal</th>
|
||||||
<th style="padding:8px 10px;text-align:center;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:90px;">Količina</th>
|
<th style="padding:8px 10px;text-align:center;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:90px;">Količina</th>
|
||||||
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:130px;">Cena/kom (din)</th>
|
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:130px;">Cena/kom (din)</th>
|
||||||
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:90px;">Marža %</th>
|
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:120px;">Marža %</th>
|
||||||
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:130px;">Prodajna/kom (din)</th>
|
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:130px;">Prodajna/kom (din)</th>
|
||||||
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:110px;">Ukupno</th>
|
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:110px;">Ukupno</th>
|
||||||
<th style="width:40px;"></th>
|
<th style="width:40px;"></th>
|
||||||
@@ -122,6 +122,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td style="padding:8px 10px;">
|
<td style="padding:8px 10px;">
|
||||||
<input type="number" :name="'prodajna[]'" x-model="stavka.prodajna"
|
<input type="number" :name="'prodajna[]'" x-model="stavka.prodajna"
|
||||||
|
@input="izracunajMarzu(stavka)"
|
||||||
min="0" step="0.01" :disabled="isMobile" style="width:100%;text-align:right;">
|
min="0" step="0.01" :disabled="isMobile" style="width:100%;text-align:right;">
|
||||||
</td>
|
</td>
|
||||||
<td style="padding:8px 10px;text-align:right;font-size:14px;font-weight:500;color:var(--tekst-glavni);">
|
<td style="padding:8px 10px;text-align:right;font-size:14px;font-weight:500;color:var(--tekst-glavni);">
|
||||||
@@ -191,7 +192,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Prodajna/kom (din)</label>
|
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Prodajna/kom (din)</label>
|
||||||
<input type="number" :name="'prodajna[]'" x-model="stavka.prodajna" min="0" step="0.01" :disabled="!isMobile" style="width:100%;">
|
<input type="number" :name="'prodajna[]'" x-model="stavka.prodajna" @input="izracunajMarzu(stavka)" min="0" step="0.01" :disabled="!isMobile" style="width:100%;">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="text-align:right;font-size:14px;font-weight:500;color:var(--tekst-glavni);">
|
<div style="text-align:right;font-size:14px;font-weight:500;color:var(--tekst-glavni);">
|
||||||
|
|||||||
Reference in New Issue
Block a user