import { createKassza , isSzamlazzError , type Kassza } from 'kassza'
import { cloudflareKvCookieStore } from 'kassza/cookie-stores'
import { r2BindingStorage , sanitizeKeySegment , storePdf } from 'kassza/storage'
interface Env {
readonly SZAMLAZZ_AGENT_KEY : string
readonly BELSO_API_TOKEN : string
readonly KASSZA_KV : KVNamespace
readonly SZAMLAK : R2Bucket
}
const PDF_FEJLECEK = { 'content-type' : 'application/pdf' , 'cache-control' : 'private, no-store' }
function kasszaKliens (env : Env ) : Kassza {
return createKassza ({
agentKey : env . SZAMLAZZ_AGENT_KEY ,
cookieStore : cloudflareKvCookieStore ( env . KASSZA_KV , { prefix : 'kassza:' , timeoutMs : 300 }) ,
})
}
function jogosult (request : Request , env : Env ) : boolean {
return (
Boolean ( env . BELSO_API_TOKEN ) &&
request . headers .get ( 'authorization' ) === `Bearer ${ env . BELSO_API_TOKEN } `
)
}
async function szamlaAdatai (kassza : Kassza , rendelesszam : string ) : Promise < Response > {
const szamla = await kassza . invoices .find ({ orderNumber : rendelesszam })
if ( ! szamla) return Response .json ({ hiba : 'Nincs ilyen számla.' } , { status : 404 })
return Response .json ({
szamlaszam : szamla . header .number ,
tipus : szamla . header .type ,
kelt : szamla . header .issueDate ,
brutto : szamla . totals .grossAmount ,
penznem : szamla . header .currency ,
sztornozva : szamla . header .reversed ?? false ,
})
}
async function szamlaPdf (
kassza : Kassza ,
env : Env ,
ctx : ExecutionContext ,
szamlaszam : string ,
) : Promise < Response > {
const tarhely = r2BindingStorage ( env . SZAMLAK , { prefix : 'szamlak' })
const kulcs = ` ${ sanitizeKeySegment (szamlaszam) } .pdf`
const mentett = await tarhely .get (kulcs)
if (mentett) return new Response (mentett , { headers : PDF_FEJLECEK })
const { pdf } = await kassza . invoices .getPdf (szamlaszam)
ctx .waitUntil (
storePdf (tarhely , kulcs , pdf) .catch ((error : unknown ) => {
console .error ( 'A PDF nem került az R2-be' , szamlaszam , error)
}) ,
)
return new Response (pdf , { headers : PDF_FEJLECEK })
}
export default {
async fetch (request , env , ctx) : Promise < Response > {
if ( ! jogosult (request , env)) return new Response ( 'Nincs jogosultság' , { status : 401 })
if ( request .method !== 'GET' ) return new Response ( 'Nem támogatott' , { status : 405 })
const { pathname } = new URL ( request .url)
const kassza = kasszaKliens (env)
try {
const rendeles = / ^ \/rendelesek\/([ ^ /] + )\/szamla $ / .exec (pathname)
if (rendeles?.[ 1 ]) return await szamlaAdatai (kassza , decodeURIComponent (rendeles[ 1 ]))
const pdf = / ^ \/szamlak\/([ ^ /] + )\.pdf $ / .exec (pathname)
if (pdf?.[ 1 ]) return await szamlaPdf (kassza , env , ctx , decodeURIComponent (pdf[ 1 ]))
return new Response ( 'Nincs ilyen útvonal' , { status : 404 })
} catch (error) {
if ( ! isSzamlazzError (error)) throw error
if ( error .isNotFound) return Response .json ({ hiba : 'Nincs ilyen számla.' } , { status : 404 })
return Response .json (
{ hiba : error .message , kategoria : error .category } ,
{ status : error .retryable ? 503 : 502 } ,
)
}
} ,
} satisfies ExportedHandler < Env >