pattanshetti / src /components /CustomerInvoice.tsx
triflix's picture
Upload 99 files
4be2b2b verified
import { forwardRef } from 'react';
import { useLanguage } from '@/contexts/LanguageContext';
import { format } from 'date-fns';
interface InvoiceItem {
particular: string;
bags: number;
grossWeightPerBag: number;
netWeight: number;
rate: number;
amount: number;
}
interface InvoiceCharges {
bardhana: boolean;
bardhanAmount: number;
hamali: boolean;
hamaliAmount: number;
adhath: boolean;
adhathPercent: number;
adhathAmount: number;
cess: number;
cessAmount: number;
gaadiBharni: number;
}
interface CustomerInvoiceProps {
shopName: string;
shopAddress: string;
shopPhone: string;
shopGST?: string;
billNumber: string;
date: string;
partyName: string;
partyAddress?: string;
partyPhone?: string;
items: InvoiceItem[];
charges: InvoiceCharges;
itemTotal: number;
grandTotal: number;
}
// This component is for customer-facing invoice
// DOES NOT SHOW: Lot numbers, purchase rates, supplier info, margins
export const CustomerInvoice = forwardRef<HTMLDivElement, CustomerInvoiceProps>(
(props, ref) => {
const { t, language } = useLanguage();
const {
shopName,
shopAddress,
shopPhone,
shopGST,
billNumber,
date,
partyName,
partyAddress,
partyPhone,
items,
charges,
itemTotal,
grandTotal,
} = props;
const formatDate = (dateString: string) => {
const d = new Date(dateString);
return format(d, 'dd/MM/yyyy');
};
return (
<div
ref={ref}
className="bg-white p-8 max-w-4xl mx-auto"
style={{ fontFamily: language === 'mr' ? 'Noto Sans Devanagari, sans-serif' : 'Arial, sans-serif' }}
>
{/* Header */}
<div className="border-b-2 border-gray-800 pb-4 mb-6">
<div className="text-center">
<h1 className="text-3xl font-bold text-gray-800 mb-2">
{shopName}
</h1>
<p className="text-sm text-gray-600">{shopAddress}</p>
<p className="text-sm text-gray-600">
{language === 'mr' ? 'फोन' : 'Phone'}: {shopPhone}
</p>
{shopGST && (
<p className="text-sm text-gray-600">
{language === 'mr' ? 'जीएसटी नंबर' : 'GST No'}: {shopGST}
</p>
)}
</div>
</div>
{/* Bill Info */}
<div className="grid grid-cols-2 gap-4 mb-6">
<div>
<p className="text-sm font-semibold text-gray-700">
{language === 'mr' ? 'बिल नंबर' : 'Bill No'}:
</p>
<p className="text-lg font-bold">{billNumber}</p>
</div>
<div className="text-right">
<p className="text-sm font-semibold text-gray-700">
{language === 'mr' ? 'तारीख' : 'Date'}:
</p>
<p className="text-lg font-bold">{formatDate(date)}</p>
</div>
</div>
{/* Party Details */}
<div className="bg-gray-50 p-4 rounded mb-6">
<p className="text-sm font-semibold text-gray-700 mb-2">
{language === 'mr' ? 'पार्टीचे नाव' : 'Party Name'}:
</p>
<p className="text-lg font-bold text-gray-800">{partyName}</p>
{partyAddress && (
<p className="text-sm text-gray-600 mt-1">{partyAddress}</p>
)}
{partyPhone && (
<p className="text-sm text-gray-600">
{language === 'mr' ? 'फोन' : 'Phone'}: {partyPhone}
</p>
)}
</div>
{/* Items Table */}
<table className="w-full mb-6">
<thead>
<tr className="border-b-2 border-gray-800">
<th className="text-left py-2 text-sm font-semibold">
{language === 'mr' ? 'तपशील' : 'Particulars'}
</th>
<th className="text-center py-2 text-sm font-semibold">
{language === 'mr' ? 'पोत्या' : 'Bags'}
</th>
<th className="text-center py-2 text-sm font-semibold">
{language === 'mr' ? 'वजन (kg)' : 'Weight (kg)'}
</th>
<th className="text-right py-2 text-sm font-semibold">
{language === 'mr' ? 'रेट' : 'Rate'}
</th>
<th className="text-right py-2 text-sm font-semibold">
{language === 'mr' ? 'रक्कम' : 'Amount'}
</th>
</tr>
</thead>
<tbody>
{items.map((item, index) => (
<tr key={index} className="border-b border-gray-200">
<td className="py-3 text-sm">{item.particular}</td>
<td className="text-center py-3 text-sm">{item.bags}</td>
<td className="text-center py-3 text-sm">{item.netWeight}</td>
<td className="text-right py-3 text-sm">₹{item.rate.toFixed(2)}</td>
<td className="text-right py-3 text-sm font-semibold">
₹{item.amount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</td>
</tr>
))}
</tbody>
</table>
{/* Charges Breakdown */}
<div className="border-t-2 border-gray-300 pt-4 mb-6">
<div className="flex justify-end">
<div className="w-1/2 space-y-2">
{/* Item Total */}
<div className="flex justify-between text-sm">
<span>{language === 'mr' ? 'माल एकूण' : 'Item Total'}:</span>
<span className="font-semibold">
₹{itemTotal.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</span>
</div>
{/* Bardhana */}
{charges.bardhana && charges.bardhanAmount > 0 && (
<div className="flex justify-between text-sm">
<span>
{language === 'mr' ? 'बर्डाणा' : 'Packing'}
({items.reduce((sum, item) => sum + item.bags, 0)} × ₹18):
</span>
<span>₹{charges.bardhanAmount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
</div>
)}
{/* Hamali */}
{charges.hamali && charges.hamaliAmount > 0 && (
<div className="flex justify-between text-sm">
<span>
{language === 'mr' ? 'हमाली' : 'Labor'}
({items.reduce((sum, item) => sum + item.bags, 0)} × ₹6):
</span>
<span>₹{charges.hamaliAmount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
</div>
)}
{/* Commission */}
{charges.adhath && charges.adhathAmount > 0 && (
<div className="flex justify-between text-sm">
<span>
{language === 'mr' ? 'अडत' : 'Commission'} ({charges.adhathPercent}%):
</span>
<span>₹{charges.adhathAmount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
</div>
)}
{/* Cess */}
{charges.cessAmount > 0 && (
<div className="flex justify-between text-sm">
<span>
{language === 'mr' ? 'सेस' : 'Cess'} ({charges.cess}%):
</span>
<span>₹{charges.cessAmount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
</div>
)}
{/* Vehicle Loading */}
{charges.gaadiBharni > 0 && (
<div className="flex justify-between text-sm">
<span>{language === 'mr' ? 'गाडी भरणी' : 'Vehicle Loading'}:</span>
<span>₹{charges.gaadiBharni.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
</div>
)}
{/* Grand Total */}
<div className="border-t-2 border-gray-800 pt-2 mt-2 flex justify-between">
<span className="text-lg font-bold">
{language === 'mr' ? 'एकूण रक्कम' : 'Grand Total'}:
</span>
<span className="text-xl font-bold text-primary">
₹{grandTotal.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</span>
</div>
</div>
</div>
</div>
{/* Footer */}
<div className="border-t border-gray-300 pt-4 mt-8">
<div className="flex justify-between items-end">
<div className="text-sm text-gray-600">
<p>{language === 'mr' ? 'नोट: कृपया रक्कम वेळेवर भरावी' : 'Note: Please pay on time'}</p>
</div>
<div className="text-center">
<div className="border-t border-gray-400 pt-2 mt-8 w-32">
<p className="text-sm font-semibold">
{language === 'mr' ? 'अधिकृत स्वाक्षरी' : 'Authorized Sign'}
</p>
</div>
</div>
</div>
</div>
{/* Print/Share Watermark */}
<div className="text-center mt-6 text-xs text-gray-400">
<p>
{language === 'mr'
? 'मिर्ची ट्रेडिंग - व्यावसायिक सॉफ्टवेअर'
: 'Mirchi Trading - Business Software'}
</p>
</div>
</div>
);
}
);
CustomerInvoice.displayName = 'CustomerInvoice';