This commit is contained in:
2026-02-15 12:51:26 +01:00
parent 29a84b899d
commit f63e793c88
5 changed files with 87 additions and 33 deletions

View File

@@ -100,20 +100,25 @@ export default async function functionRoutes(server: FastifyInstance) {
server.get('/functions/check-zip/:zip', async (req, reply) => { server.get('/functions/check-zip/:zip', async (req, reply) => {
const { zip } = req.params as { zip: string } const { zip } = req.params as { zip: string }
const normalizedZip = String(zip || "").replace(/\D/g, "")
if (!zip) { if (normalizedZip.length !== 5) {
return reply.code(400).send({ error: 'ZIP is required' }) return reply.code(400).send({ error: 'ZIP must contain exactly 5 digits' })
} }
try { try {
//@ts-ignore const data = await server.db
const data = await server.db.select().from(citys).where(eq(citys.zip,zip)) .select()
.from(citys)
.where(eq(citys.zip, Number(normalizedZip)))
if (!data) { if (!data.length) {
return reply.code(404).send({ error: 'ZIP not found' }) return reply.code(404).send({ error: 'ZIP not found' })
} }
const city = data[0]
//districtMap //districtMap
const bundeslaender = [ const bundeslaender = [
{ code: 'DE-BW', name: 'Baden-Württemberg' }, { code: 'DE-BW', name: 'Baden-Württemberg' },
@@ -137,9 +142,8 @@ export default async function functionRoutes(server: FastifyInstance) {
return reply.send({ return reply.send({
...data, ...city,
//@ts-ignore state_code: bundeslaender.find(i => i.name === city.countryName)?.code || null
state_code: bundeslaender.find(i => i.name === data.countryName)
}) })
} catch (err) { } catch (err) {
console.log(err) console.log(err)

View File

@@ -50,12 +50,23 @@ export const useFunctions = () => {
} }
const useZipCheck = async (zip) => { const useZipCheck = async (zip) => {
const returnData = await useNuxtApp().$api(`/api/functions/check-zip/${zip}`, { const normalizedZip = String(zip || "").replace(/\D/g, "")
if (!normalizedZip || normalizedZip.length > 5) {
return null
}
const lookupZip = normalizedZip.padStart(5, "0")
try {
const data = await useNuxtApp().$api(`/api/functions/check-zip/${lookupZip}`, {
method: "GET", method: "GET",
}) })
return {
return returnData ...data,
zip: String(data?.zip ?? lookupZip).replace(/\D/g, "").padStart(5, "0")
}
} catch (e) {
return null
}
} }
@@ -75,5 +86,5 @@ export const useFunctions = () => {
} }
return {getWorkingTimesEvaluationData, useNextNumber, useCreateTicket, useBankingGenerateLink, useZipCheck, useBankingCheckInstitutions, useBankingListRequisitions, useCreatePDF,useGetInvoiceData, useSendTelegramNotification} return {getWorkingTimesEvaluationData, useNextNumber, useBankingGenerateLink, useZipCheck, useBankingCheckInstitutions, useBankingListRequisitions, useCreatePDF}
} }

View File

@@ -633,6 +633,27 @@ const removePosition = (id) => {
} }
const normalizeZip = (value) => String(value || "").replace(/\D/g, "")
const sanitizeAddressZipInput = () => {
itemInfo.value.address.zip = normalizeZip(itemInfo.value.address.zip)
}
const checkAddressZip = async () => {
const zip = normalizeZip(itemInfo.value.address.zip)
itemInfo.value.address.zip = zip
if (![4, 5].includes(zip.length)) return
const zipData = await useFunctions().useZipCheck(zip)
if (zipData?.zip) {
itemInfo.value.address.zip = zipData.zip
}
if (zipData?.short) {
itemInfo.value.address.city = zipData.short
}
}
const findDocumentErrors = computed(() => { const findDocumentErrors = computed(() => {
let errors = [] let errors = []
@@ -640,15 +661,15 @@ const findDocumentErrors = computed(() => {
if (itemInfo.value.contact === null) errors.push({message: "Es ist kein Kontakt ausgewählt", type: "info"}) if (itemInfo.value.contact === null) errors.push({message: "Es ist kein Kontakt ausgewählt", type: "info"})
if (itemInfo.value.letterhead === null) errors.push({message: "Es ist kein Briefpapier ausgewählt", type: "breaking"}) if (itemInfo.value.letterhead === null) errors.push({message: "Es ist kein Briefpapier ausgewählt", type: "breaking"})
if (itemInfo.value.created_by === null || !itemInfo.value.created_by) errors.push({message: "Es ist kein Mitarbeiter ausgewählt", type: "breaking"}) if (itemInfo.value.created_by === null || !itemInfo.value.created_by) errors.push({message: "Es ist kein Mitarbeiter ausgewählt", type: "breaking"})
if (itemInfo.value.address.street === null) errors.push({ if (!itemInfo.value.address.street) errors.push({
message: "Es ist keine Straße im Adressat angegeben", message: "Es ist keine Straße im Adressat angegeben",
type: "breaking" type: "breaking"
}) })
if (itemInfo.value.address.zip === null) errors.push({ if (!itemInfo.value.address.zip) errors.push({
message: "Es ist keine Postleitzahl im Adressat angegeben", message: "Es ist keine Postleitzahl im Adressat angegeben",
type: "breaking" type: "breaking"
}) })
if (itemInfo.value.address.city === null) errors.push({ if (!itemInfo.value.address.city) errors.push({
message: "Es ist keine Stadt im Adressat angegeben", message: "Es ist keine Stadt im Adressat angegeben",
type: "breaking" type: "breaking"
}) })
@@ -1893,6 +1914,11 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
<UInput <UInput
class="flex-auto" class="flex-auto"
v-model="itemInfo.address.zip" v-model="itemInfo.address.zip"
type="text"
inputmode="numeric"
maxlength="5"
@input="sanitizeAddressZipInput"
@change="checkAddressZip"
:placeholder="itemInfo.customer ? customers.find(i => i.id === itemInfo.customer).infoData.zip : 'PLZ'" :placeholder="itemInfo.customer ? customers.find(i => i.id === itemInfo.customer).infoData.zip : 'PLZ'"
:color="itemInfo.address.zip ? 'primary' : 'rose'" :color="itemInfo.address.zip ? 'primary' : 'rose'"
/> />

View File

@@ -109,9 +109,12 @@ function recalculateWeeklyHours() {
const checkZip = async () => { const checkZip = async () => {
const zipData = await useFunctions().useZipCheck(profile.value.address_zip) const zipData = await useFunctions().useZipCheck(profile.value.address_zip)
if (zipData) {
profile.value.address_zip = zipData.zip || profile.value.address_zip
profile.value.address_city = zipData.short profile.value.address_city = zipData.short
profile.value.state_code = zipData.state_code profile.value.state_code = zipData.state_code
} }
}
onMounted(fetchProfile) onMounted(fetchProfile)
@@ -314,5 +317,3 @@ onMounted(fetchProfile)
<USkeleton v-if="pending" height="300px" /> <USkeleton v-if="pending" height="300px" />
</UDashboardPanelContent> </UDashboardPanelContent>
</template> </template>

View File

@@ -333,10 +333,14 @@ export const useDataStore = defineStore('data', () => {
{ {
key: "infoData.zip", key: "infoData.zip",
label: "Postleitzahl", label: "Postleitzahl",
inputType: "number", inputType: "text",
inputChangeFunction: async function (row) { inputChangeFunction: async function (row) {
if(row.infoData.zip) { const zip = String(row.infoData.zip || "").replace(/\D/g, "")
row.infoData.city = (await useFunctions().useZipCheck(row.infoData.zip)).short row.infoData.zip = zip
if ([4, 5].includes(zip.length)) {
const zipData = await useFunctions().useZipCheck(zip)
row.infoData.zip = zipData?.zip || row.infoData.zip
row.infoData.city = zipData?.short || row.infoData.city
} }
}, },
disabledInTable: true, disabledInTable: true,
@@ -1291,11 +1295,15 @@ export const useDataStore = defineStore('data', () => {
{ {
key: "infoData.zip", key: "infoData.zip",
label: "Postleitzahl", label: "Postleitzahl",
inputType: "number", inputType: "text",
disabledInTable: true, disabledInTable: true,
inputChangeFunction: async function (row) { inputChangeFunction: async function (row) {
if(row.infoData.zip) { const zip = String(row.infoData.zip || "").replace(/\D/g, "")
row.infoData.city = (await useFunctions().useZipCheck(row.infoData.zip)).short row.infoData.zip = zip
if ([4, 5].includes(zip.length)) {
const zipData = await useFunctions().useZipCheck(zip)
row.infoData.zip = zipData?.zip || row.infoData.zip
row.infoData.city = zipData?.short || row.infoData.city
} }
}, },
}, },
@@ -1474,12 +1482,16 @@ export const useDataStore = defineStore('data', () => {
{ {
key: "info_data.zip", key: "info_data.zip",
label: "Postleitzahl", label: "Postleitzahl",
inputType: "number", inputType: "text",
disabledInTable: true, disabledInTable: true,
inputColumn: "Ort", inputColumn: "Ort",
inputChangeFunction: async function (row) { inputChangeFunction: async function (row) {
if(row.infoData.zip) { const zip = String(row.info_data.zip || "").replace(/\D/g, "")
row.infoData.city = (await useFunctions().useZipCheck(row.infoData.zip)).short row.info_data.zip = zip
if ([4, 5].includes(zip.length)) {
const zipData = await useFunctions().useZipCheck(zip)
row.info_data.zip = zipData?.zip || row.info_data.zip
row.info_data.city = zipData?.short || row.info_data.city
} }
}, },
}, },