18 Commits

Author SHA1 Message Date
65588686c7 Merge pull request 'fix(documents): normalize units when selecting and loading rows' (#230) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 48s
Build and Release FEDEO / build-and-release (push) Successful in 6m3s
Reviewed-on: #230
2026-09-25 09:54:08 +00:00
8f06d06037 fix(documents): normalize units when selecting and loading rows
All checks were successful
Build and Release FEDEO / verify (push) Successful in 49s
Build and Release FEDEO / build-and-release (push) Successful in 5m50s
2026-09-25 11:42:17 +02:00
fcf9cc3fc9 Merge pull request 'dev' (#229) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 49s
Build and Release FEDEO / build-and-release (push) Successful in 6m6s
Reviewed-on: #229
2026-09-25 09:24:39 +00:00
20091143d2 Merge pull request 'dev' (#228) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 45s
Build and Release FEDEO / build-and-release (push) Successful in 6m5s
Reviewed-on: #228
2026-09-23 17:20:58 +00:00
f708d0a2b2 Merge pull request 'dev' (#227) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 44s
Build and Release FEDEO / build-and-release (push) Successful in 6m7s
Reviewed-on: #227
2026-09-23 16:15:44 +00:00
7e9f4409f6 Merge pull request 'dev' (#226) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 33s
Build and Release FEDEO / build-and-release (push) Successful in 6m10s
Reviewed-on: #226
2026-09-23 14:57:40 +00:00
2e63af1aa2 Merge pull request 'fix(release): stream large migration checksums from git' (#225) from flfeders/codex/release-migration-checksums into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 25s
Build and Release FEDEO / build-and-release (push) Successful in 5m59s
Reviewed-on: #225
2026-09-23 14:09:57 +00:00
5ebd2d508c Merge pull request 'fix(release): exclude legacy main history from commit checks' (#224) from dev into main
Some checks failed
Build and Release FEDEO / verify (push) Successful in 23s
Build and Release FEDEO / build-and-release (push) Failing after 5m57s
Reviewed-on: #224
2026-09-23 13:03:36 +00:00
9128fbb165 Merge pull request 'fix(ci): build dev images without repository write access' (#221) from dev into main
Some checks failed
Build and Release FEDEO / verify (push) Failing after 26s
Build and Release FEDEO / build-and-release (push) Has been skipped
Reviewed-on: #221
2026-09-20 16:25:38 +00:00
8473221c13 Merge pull request '3.0.0' (#220) from dev into main
Some checks failed
Build and Release FEDEO / verify (push) Failing after 22s
Build and Release FEDEO / build-and-release (push) Has been skipped
Reviewed-on: #220
2026-09-20 16:10:46 +00:00
e7554fa2cc .gitea/ISSUE_TEMPLATE/feature_request.md aktualisiert
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 16s
Build and Push Docker Images / build-frontend (push) Successful in 16s
2026-01-22 17:42:28 +00:00
7c1fabf58a .gitea/ISSUE_TEMPLATE/bug_report.md aktualisiert
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 17s
Build and Push Docker Images / build-frontend (push) Successful in 16s
2026-01-22 17:40:58 +00:00
1203b6cbd1 .gitea/ISSUE_TEMPLATE/bug_report.md aktualisiert
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 16s
Build and Push Docker Images / build-frontend (push) Successful in 16s
2026-01-15 11:39:03 +00:00
525f2906fb .gitea/ISSUE_TEMPLATE/feature_request.md aktualisiert
Some checks failed
Build and Push Docker Images / build-frontend (push) Has been cancelled
Build and Push Docker Images / build-backend (push) Has been cancelled
2026-01-15 11:38:50 +00:00
b105382abf .gitea/ISSUE_TEMPLATE/bug_report.md aktualisiert
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 16s
Build and Push Docker Images / build-frontend (push) Successful in 15s
2026-01-15 11:38:00 +00:00
b1cdec7d17 Merge pull request 'Added feature request template' (#62) from dev into main
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 17s
Build and Push Docker Images / build-frontend (push) Successful in 16s
Reviewed-on: #62
2026-01-15 11:31:57 +00:00
f1d512b2e5 Merge pull request 'dev' (#61) from dev into main
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 17s
Build and Push Docker Images / build-frontend (push) Successful in 16s
Reviewed-on: #61
2026-01-15 11:29:15 +00:00
db21b43120 Merge pull request 'dev' (#40) from dev into main
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 18s
Build and Push Docker Images / build-frontend (push) Successful in 16s
Reviewed-on: #40
2026-01-08 22:21:06 +00:00
4 changed files with 114 additions and 41 deletions

View File

@@ -2,37 +2,18 @@
name: 🐛 Bug Report
about: Erstelle einen Bericht, um uns zu helfen, das Projekt zu verbessern.
title: '[BUG] '
labels: bug
labels: Problem
assignees: ''
---
**Beschreibung**
Eine klare und prägnante Beschreibung des Fehlers.
**Reproduktion**
Schritte, um den Fehler zu reproduzieren:
Entweder:
1. Gehe zu '...'
2. Klicke auf '...'
3. Scrolle runter zu '...'
4. Siehe Fehler
Oder Link zur Seite
**Erwartetes Verhalten**
Eine klare Beschreibung dessen, was du erwartet hast.
**Screenshots**
Falls zutreffend, füge hier Screenshots oder Gifs hinzu, um das Problem zu verdeutlichen.
**Achtung: Achte bitte auf Datenschutz deiner Daten sowie der Daten deiner Kunden. Sollten ein Screenshot nur mit Daten möglich sein, schwärze diese bitte vor dem Upload.**
**Umgebung:**
- Betriebssystem: [z.B. Windows, macOS, Linux]
- Browser / Version (falls relevant): [z.B. Chrome 120]
- Projekt-Version: [z.B. v1.0.2]
**Zusätzlicher Kontext**
Füge hier alle anderen Informationen zum Problem hinzu.

View File

@@ -2,19 +2,16 @@
name: ✨ Feature Request
about: Schlage eine Idee für dieses Projekt vor.
title: '[FEATURE] '
labels: enhancement
labels: Funktionswunsch
assignees: ''
---
**Ist dein Feature-Wunsch mit einem Problem verbunden?**
Eine klare Beschreibung des Problems (z.B. "Ich bin immer genervt, wenn...").
**Lösungsvorschlag**
Eine klare Beschreibung dessen, was du dir wünschst und wie es funktionieren soll.
**Alternativen**
Hast du über alternative Lösungen oder Workarounds nachgedacht?
**Zusätzlicher Kontext**
Hier ist Platz für weitere Informationen, Skizzen oder Beispiele von anderen Tools.

View File

@@ -333,6 +333,13 @@ const normalizeEntityId = (value) => {
}
return typeof value === "object" ? (value.id ?? null) : value
}
const normalizeUnitId = (unit) => {
const value = unit && typeof unit === "object" ? unit.id : unit
if (typeof value !== "number" && typeof value !== "string") return null
const id = Number(value)
return Number.isSafeInteger(id) && id > 0 ? id : null
}
const normalizeCreatedDocumentRow = (row) => {
let normalizedRow = row
@@ -359,6 +366,7 @@ const normalizeCreatedDocumentRow = (row) => {
return {
...normalizedRow,
id: normalizedRow.id || uuidv4(),
unit: normalizeUnitId(normalizedRow.unit),
costCentre: normalizedRow.costCentre || normalizedRow.costcentre || null,
purchasePrice: Number(normalizedRow.purchasePrice || 0),
linkedEntitys: Array.isArray(normalizedRow.linkedEntitys) ? normalizedRow.linkedEntitys : [],
@@ -689,6 +697,7 @@ const setupPage = async () => {
}
itemInfo.value.rows = normalizeCreatedDocumentRows(itemInfo.value.rows)
loaded.value = true
}
@@ -2035,19 +2044,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
if (row.service) {
console.log(service)
if(service.unit) {
row.unit = service.unit
} else {
let selectedService = services.value.find(i => i.id === row.service)
console.log(selectedService)
if(selectedService.unit?.id) {
row.unit = selectedService.unit.id
} else {
row.unit = selectedService.unit
}
}
row.unit = normalizeUnitId(service?.unit ?? services.value.find(i => i.id === row.service)?.unit)
//row.unit = service.unit ? service.unit : services.value.find(i => i.id === row.service).unit
row.inputPrice = ((service.sellingPriceComposed.total || service.sellingPrice) ? (service.sellingPriceComposed.total || service.sellingPrice) : (services.value.find(i => i.id === row.service).sellingPriceComposed.total || services.value.find(i => i.id === row.service).sellingPrice))
row.description = service.description ? service.description : (services.value.find(i => i.id === row.service) ? services.value.find(i => i.id === row.service).description : "")
row.costCentre = service.costcentre || services.value.find(i => i.id === row.service)?.costcentre || itemInfo.value.costcentre
@@ -2061,7 +2059,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
if (row.product) {
console.log("Product Detected")
row.unit = product.unit ? product.unit : products.value.find(i => i.id === row.product).unit
row.unit = normalizeUnitId(product?.unit ?? products.value.find(i => i.id === row.product)?.unit)
row.inputPrice = (product.selling_price ? product.selling_price : products.value.find(i => i.id === row.product).selling_price)
row.costCentre = row.costCentre || itemInfo.value.costcentre
//row.price = Number((row.originalPrice * (1 + itemInfo.value.customSurchargePercentage /100)).toFixed(2))

View File

@@ -0,0 +1,97 @@
const { test } = require('node:test')
const assert = require('node:assert/strict')
const fs = require('node:fs')
const vm = require('node:vm')
const ts = require('typescript')
const dayjs = require('dayjs')
const { parse } = require('@vue/compiler-sfc')
const { descriptor } = parse(fs.readFileSync(`${__dirname}/../pages/createDocument/edit/[[id]].vue`, 'utf8'))
const script = ts.createSourceFile('document-editor.js', descriptor.scriptSetup.content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS)
const handlers = new Set(['normalizeEntityId', 'normalizeUnitId', 'normalizeCreatedDocumentRow', 'normalizeCreatedDocumentRows', 'normalizeTaxTypeValue', 'setupPage', 'setRowData'])
const source = script.statements
.filter(statement => ts.isVariableStatement(statement) && statement.declarationList.declarations.some(declaration => handlers.has(declaration.name.getText(script))))
.map(statement => statement.getText(script)).join('\n')
function fixture(unit) {
const ref = value => ({ value })
const product = { id: 20, name: 'Artikel', unit, selling_price: 10, tax_percentage: 19 }
const service = { id: 30, name: 'Leistung', unit, sellingPrice: 20, sellingPriceComposed: {}, taxPercentage: 19 }
const context = vm.createContext({
dayjs, uuidv4: () => 'row-id', console: { log() {} },
products: ref([product]), services: ref([service]),
productcategories: ref([]), servicecategories: ref([]),
itemInfo: ref({ type: 'invoices', taxType: 'Standard', rows: [], agriculture: {} }),
route: { params: {}, query: {} }, loaded: ref(false), templateName: ref(''),
taxTypeItems: [{ key: 'Standard' }],
dataStore: { documentTypesForCreation: { invoices: { labelSingle: 'Rechnung' } } },
setupData: async () => {}, setDocumentTypeConfig() {}, setContactPersonData: async () => {},
checkCompatibilityWithInputPrice() {}, updateCustomSurcharge() {},
useEntities: relation => ({
select: async () => relation === 'products' ? [product] : [service],
selectSingle: async () => {
if (relation === 'documenttemplates') return { name: 'Vorlage', documentType: 'invoices', templateData: { rows: [{ id: 'saved-row', mode: 'normal', product: 20, unit }] } }
return { id: 40, type: 'invoices', taxType: 'Standard', rows: [{ id: 'saved-row', mode: 'normal', product: 20, unit }] }
},
}),
})
vm.runInContext(source, context)
return { context, run: code => vm.runInContext(code, context) }
}
const formats = [1, { id: 1, name: 'Stück' }, '1', { id: '1', name: 'Stück' }]
test('article and service selection resolve relation objects and legacy IDs to a selectable unit', async () => {
for (const unit of formats) {
const { run } = fixture(unit)
for (const entity of ['product', 'service']) {
run(`itemInfo.value.rows = [{ ${entity}: ${entity === 'product' ? 20 : 30} }]`)
await run('setRowData(itemInfo.value.rows[0])')
assert.equal(run('itemInfo.value.rows[0].unit'), 1, `${entity}: ${JSON.stringify(unit)}`)
}
}
})
test('article and service modal results retain their selected unit', async () => {
for (const unit of formats) {
const { run } = fixture(unit)
run('itemInfo.value.rows = [{}]')
await run('setRowData(itemInfo.value.rows[0], null, products.value[0])')
assert.equal(run('itemInfo.value.rows[0].unit'), 1)
run('itemInfo.value.rows = [{}]')
await run('setRowData(itemInfo.value.rows[0], services.value[0], null)')
assert.equal(run('itemInfo.value.rows[0].unit'), 1)
}
})
test('saved documents and both template entry points restore units without overwriting the stored choice', async () => {
for (const route of [{ params: { id: 40 }, query: {} }, { params: {}, query: { templateId: 50 } }, { params: {}, query: { templateFromDocument: 40 } }]) {
for (const unit of formats) {
const { context, run } = fixture(unit)
context.route = route
context.products.value[0].unit = { id: 2, name: 'Meter' }
await run('setupPage()')
assert.equal(run('loaded.value'), true)
assert.equal(run('itemInfo.value.rows[0].unit'), 1, JSON.stringify(route))
assert.equal(run('itemInfo.value.rows[0].id'), 'saved-row')
}
}
})
test('imported JSON rows preserve quantity, prices and the stored unit', () => {
const { run, context } = fixture(1)
context.rows = [JSON.stringify({ id: 'imported', mode: 'normal', unit: { id: '1' }, quantity: 2.5, price: 12.34 })]
const row = run('normalizeCreatedDocumentRows(rows)[0]')
assert.equal(row.unit, 1)
assert.equal(row.id, 'imported')
assert.equal(row.quantity, 2.5)
assert.equal(row.price, 12.34)
})
test('missing and malformed units remain unselected', () => {
const { run, context } = fixture(1)
for (const unit of [null, undefined, '', {}, { id: null }, 'invalid', 0, -1, true]) {
context.row = { unit }
assert.equal(run('normalizeCreatedDocumentRow(row).unit'), null)
}
})