Commercial Invoice Generator
blockdashboardB2B cross-border commercial invoice generator with HTS tariff codes, EORI tax identifiers, and CIF valuation totals.
Installation
$pnpm dlx shadcn-vue@latest add https://uipkge.dev/r/vue/commercial-invoice-generator.json$npx shadcn-vue@latest add https://uipkge.dev/r/vue/commercial-invoice-generator.json$yarn dlx shadcn-vue@latest add https://uipkge.dev/r/vue/commercial-invoice-generator.json$bunx shadcn-vue@latest add https://uipkge.dev/r/vue/commercial-invoice-generator.jsonNamed registry:
npx shadcn-vue@latest add @uipkge/commercial-invoice-generatorInstalls to:app/components/blocks/commercial-invoice-generator/Variants
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
invoiceNumber | string | 'INV-EXP-2026-9042' | optional |
incoterms | string | 'DAP (Delivered at Place)' | optional |
currency | string | 'USD' | optional |
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
InvoiceIteminterface InvoiceItem {
id: string
description: string
htsCode: string
countryOfOrigin: string
qty: number
unitPrice: number
weightKg: number
}Files installed (2)
app/components/blocks/commercial-invoice-generator/CommercialInvoiceGenerator.vue11.1 kB
<script setup lang="ts"> import { ref, computed } from 'vue' import { Download, Plus, Printer, ShieldCheck, Trash2 } from 'lucide-vue-next' import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Badge } from '@/components/ui/badge' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' export interface InvoiceItem { id: string description: string htsCode: string countryOfOrigin: string qty: number unitPrice: number weightKg: number } export interface CommercialInvoiceProps { invoiceNumber?: string incoterms?: string currency?: string } const props = withDefaults(defineProps<CommercialInvoiceProps>(), { invoiceNumber: 'INV-EXP-2026-9042', incoterms: 'DAP (Delivered at Place)', currency: 'USD', }) const isSigned = ref(false) const items = ref<InvoiceItem[]>([ { id: 'inv-1', description: 'Precision CNC Machined Aluminum Actuator Housing', htsCode: '8479.90.94', countryOfOrigin: 'US', qty: 50, unitPrice: 185.0, weightKg: 24.5, }, { id: 'inv-2', description: 'Brushless DC High-Torque Servo Motor 48V', htsCode: '8501.31.20', countryOfOrigin: 'DE', qty: 25, unitPrice: 320.0, weightKg: 31.0, }, { id: 'inv-3', description: 'Industrial Polyurethane Seal Gasket Kit', htsCode: '3926.90.99', countryOfOrigin: 'JP', qty: 100, unitPrice: 14.5, weightKg: 4.2, }, ]) const subtotal = computed(() => items.value.reduce((sum, item) => sum + item.qty * item.unitPrice, 0)) const totalWeightKg = computed(() => items.value.reduce((sum, item) => sum + item.weightKg, 0)) const freightCharges = ref(450.0) const insuranceCharges = ref(85.0) const grandTotal = computed(() => subtotal.value + freightCharges.value + insuranceCharges.value) function addItem() { items.value.push({ id: `inv-${Date.now()}`, description: 'General Industrial Hardware / Fasteners', htsCode: '7318.15.20', countryOfOrigin: 'US', qty: 10, unitPrice: 25.0, weightKg: 2.0, }) } function removeItem(id: string) { items.value = items.value.filter((i) => i.id !== id) } </script> <template> <div data-slot="commercial-invoice-generator" class="w-full space-y-6"> <!-- Top Action Card --> <Card> <CardHeader class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between"> <div class="space-y-1"> <div class="flex items-center gap-2"> <span class="text-foreground font-mono text-sm font-semibold">{{ invoiceNumber }}</span> <Badge variant="outline">{{ incoterms }}</Badge> <Badge :variant="isSigned ? 'default' : 'secondary'"> {{ isSigned ? 'Customs Declared & Sealed' : 'Draft Declaration' }} </Badge> </div> <CardTitle class="text-xl">International Commercial Customs Invoice</CardTitle> <CardDescription> Harmonized Tariff Schedule (HTS) compliance declaration for international customs clearance. </CardDescription> </div> <div class="flex items-center gap-2"> <Button variant="outline" size="sm" class="gap-1.5"> <Printer class="size-3.5" /> Print Form </Button> <Button variant="outline" size="sm" class="gap-1.5"> <Download class="size-3.5" /> Export EDI / PDF </Button> <Button v-if="!isSigned" variant="default" size="sm" class="gap-1.5" @click="isSigned = true"> <ShieldCheck class="size-3.5" /> Sign Customs Declaration </Button> <Button v-else variant="secondary" size="sm" class="gap-1.5" @click="isSigned = false"> Unlock Edit </Button> </div> </CardHeader> <CardContent class="border-border grid grid-cols-1 gap-6 border-t pt-4 sm:grid-cols-2"> <!-- Exporter / Shipper --> <div class="border-border space-y-1 rounded-lg border p-3"> <div class="text-muted-foreground text-xs font-semibold">EXPORTER / SHIPPER (CONSIGNOR)</div> <div class="text-foreground text-sm font-medium">Global Aerospace Components Inc.</div> <div class="text-muted-foreground text-xs">9400 Aeronautics Way, Dock 4</div> <div class="text-muted-foreground text-xs">Seattle, WA 98108, United States</div> <div class="text-muted-foreground pt-1 font-mono text-xs">EORI / Tax ID: US-EIN-98441029</div> </div> <!-- Importer / Consignee --> <div class="border-border space-y-1 rounded-lg border p-3"> <div class="text-muted-foreground text-xs font-semibold">IMPORTER / BUYER (CONSIGNEE)</div> <div class="text-foreground text-sm font-medium">Nordic Robotics Systems AB</div> <div class="text-muted-foreground text-xs">Industrigatan 18, Byggnad B</div> <div class="text-muted-foreground text-xs">SE-417 56 Göteborg, Sweden</div> <div class="text-muted-foreground pt-1 font-mono text-xs">VAT / EORI: SE556012345601</div> </div> </CardContent> </Card> <!-- Line Items Table --> <Card> <CardHeader class="flex flex-col gap-3 pb-3 sm:flex-row sm:items-center sm:justify-between"> <div> <CardTitle class="text-base font-semibold">Customs Line Item Breakdown</CardTitle> <CardDescription> Total Gross Net Weight: <span class="font-mono">{{ totalWeightKg.toFixed(1) }} kg</span> · Currency: {{ currency }} </CardDescription> </div> <Button v-if="!isSigned" variant="outline" size="sm" class="gap-1.5" @click="addItem"> <Plus class="size-3.5" /> Add Line Item </Button> </CardHeader> <CardContent class="p-0"> <Table> <TableHeader> <TableRow> <TableHead class="w-[300px]">Goods Description</TableHead> <TableHead>HTS / Tariff Code</TableHead> <TableHead>Origin (COO)</TableHead> <TableHead class="text-right">Net Wt (kg)</TableHead> <TableHead class="w-[90px] text-right">Qty</TableHead> <TableHead class="w-[120px] text-right">Unit Price</TableHead> <TableHead class="text-right">Customs Total</TableHead> <TableHead v-if="!isSigned" class="w-[40px]"></TableHead> </TableRow> </TableHeader> <TableBody> <TableRow v-for="item in items" :key="item.id"> <!-- Description --> <TableCell> <Input v-if="!isSigned" v-model="item.description" class="h-8 text-xs" /> <span v-else class="text-foreground font-medium">{{ item.description }}</span> </TableCell> <!-- HTS Code --> <TableCell> <Input v-if="!isSigned" v-model="item.htsCode" class="h-8 w-28 font-mono text-xs" /> <span v-else class="font-mono text-xs font-semibold">{{ item.htsCode }}</span> </TableCell> <!-- Country of Origin --> <TableCell> <Input v-if="!isSigned" v-model="item.countryOfOrigin" class="h-8 w-16 text-center font-mono text-xs uppercase" /> <span v-else class="bg-muted rounded px-1.5 py-0.5 font-mono text-xs font-medium">{{ item.countryOfOrigin }}</span> </TableCell> <!-- Net Weight --> <TableCell class="text-right"> <Input v-if="!isSigned" v-model.number="item.weightKg" type="number" step="0.1" class="h-8 text-right font-mono text-xs" /> <span v-else class="text-muted-foreground font-mono text-xs">{{ item.weightKg.toFixed(1) }}</span> </TableCell> <!-- Qty --> <TableCell class="text-right"> <Input v-if="!isSigned" v-model.number="item.qty" type="number" min="1" class="h-8 text-right font-mono text-xs" /> <span v-else class="font-mono text-sm">{{ item.qty }}</span> </TableCell> <!-- Unit Price --> <TableCell class="text-right"> <Input v-if="!isSigned" v-model.number="item.unitPrice" type="number" step="0.01" class="h-8 text-right font-mono text-xs" /> <span v-else class="font-mono text-sm">${{ item.unitPrice.toFixed(2) }}</span> </TableCell> <!-- Line Total --> <TableCell class="text-foreground text-right font-mono text-sm font-semibold"> ${{ (item.qty * item.unitPrice).toFixed(2) }} </TableCell> <!-- Delete --> <TableCell v-if="!isSigned"> <Button variant="ghost" size="icon" class="text-muted-foreground hover:text-destructive size-8" @click="removeItem(item.id)" > <Trash2 class="size-3.5" /> </Button> </TableCell> </TableRow> </TableBody> </Table> </CardContent> <!-- Totals & Tariff Summary Footer --> <CardFooter class="border-border flex flex-col gap-4 border-t pt-4 sm:flex-row sm:items-start sm:justify-between"> <div class="text-muted-foreground space-y-1 text-xs sm:max-w-md"> <p class="text-foreground font-medium">Exporter Declaration & Legal Certification:</p> <p> I hereby certify that the information on this invoice is true and correct and that the contents of this shipment are as stated above. </p> </div> <div class="w-full space-y-1.5 sm:w-72"> <div class="text-muted-foreground flex justify-between text-xs"> <span>FOB Line Subtotal:</span> <span class="text-foreground font-mono font-medium">${{ subtotal.toFixed(2) }}</span> </div> <div class="text-muted-foreground flex justify-between text-xs"> <span>International Freight (Air):</span> <span class="text-foreground font-mono font-medium">${{ freightCharges.toFixed(2) }}</span> </div> <div class="text-muted-foreground flex justify-between text-xs"> <span>Cargo Marine Insurance:</span> <span class="text-foreground font-mono font-medium">${{ insuranceCharges.toFixed(2) }}</span> </div> <div class="border-border text-foreground flex justify-between border-t pt-2 text-sm font-semibold"> <span>Declared CIF Value:</span> <span class="font-mono text-base font-bold">${{ grandTotal.toFixed(2) }} USD</span> </div> </div> </CardFooter> </Card> </div> </template>app/components/blocks/commercial-invoice-generator/index.ts0.2 kB
export { default as CommercialInvoiceGenerator } from './CommercialInvoiceGenerator.vue' export type { InvoiceItem, CommercialInvoiceProps } from './CommercialInvoiceGenerator.vue'
Raw manifest:https://uipkge.dev/r/vue/commercial-invoice-generator.json