Ignore:
Timestamp:
02/26/25 10:05:32 (6 weeks ago)
Author:
Naum Shapkarovski <naumshapkarovski@…>
Branches:
main
Children:
299af01
Parents:
5d6f37a
Message:

feat: implement employees

Location:
src/sections/invoice
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • src/sections/invoice/invoice-details.tsx

    r5d6f37a r057453c  
    1818import { fCurrency } from 'src/utils/format-number';
    1919// types
    20 import { Invoice } from 'mvpmasters-shared';
     20import { Invoice } from 'src/schemas';
    2121// components
    2222import Label from 'src/components/label';
     
    2828import { getQuantityType } from 'src/utils/get-invoice-quantity-type';
    2929import InvoiceToolbar from './invoice-toolbar';
     30import { updateInvoice } from 'src/api/invoice';
    3031
    3132// ----------------------------------------------------------------------
     
    5960  const handleChangeStatus = useCallback(
    6061    async (event: React.ChangeEvent<HTMLInputElement>) => {
    61       await updateDocument(collections.invoice, invoice.id, { status: event.target.value });
     62      // await updateDocument(collections.invoice, invoice.id, { status: event.target.value });
     63      await updateInvoice(invoice.id, {
     64        status: event.target.value as 'draft' | 'processing' | 'pending' | 'overdue' | 'paid',
     65      });
    6266      mutate([collections.invoice, invoice.id]);
    6367    },
     
    240244            {invoice.invoiceTo.name}
    241245            <br />
    242             {!!invoice.invoiceTo.companyId && (
     246            {!!invoice.invoiceTo.companyNumber && (
    243247              <>
    244                 Company ID: {invoice.invoiceTo.companyId}
     248                Company ID: {invoice.invoiceTo.companyNumber}
    245249                <br />
    246250              </>
     
    257261              Date Issued
    258262            </Typography>
    259             {fDate(invoice.createDate.toDate())}
     263            {fDate(invoice.createDate)}
    260264          </Stack>
    261265
     
    264268              Due Date
    265269            </Typography>
    266             {fDate(invoice.dueDate.toDate())}
     270            {fDate(invoice.dueDate)}
    267271          </Stack>
    268272        </Box>
  • src/sections/invoice/invoice-ee-pdf.tsx

    r5d6f37a r057453c  
    55import { fCurrency } from 'src/utils/format-number';
    66// types
    7 import { Invoice } from 'mvpmasters-shared';
     7import { Invoice } from 'src/schemas';
    88import { createFullAddress } from 'src/utils/create-full-address';
    99import { getQuantityType } from 'src/utils/get-invoice-quantity-type';
     
    229229          <View style={styles.col6}>
    230230            <Text style={[styles.subtitle1, styles.mb4]}>Date Issued</Text>
    231             <Text style={styles.body2}>{fDate(createDate.toDate())}</Text>
     231            <Text style={styles.body2}>{fDate(createDate)}</Text>
    232232          </View>
    233233          <View style={styles.col6}>
    234234            <Text style={[styles.subtitle1, styles.mb4]}>Due date</Text>
    235             <Text style={styles.body2}>{fDate(dueDate.toDate())}</Text>
     235            <Text style={styles.body2}>{fDate(dueDate)}</Text>
    236236          </View>
    237237        </View>
  • src/sections/invoice/invoice-mk-pdf.tsx

    r5d6f37a r057453c  
    55import { fCurrency } from 'src/utils/format-number';
    66// types
    7 import { Invoice } from 'mvpmasters-shared';
     7import { Invoice } from 'src/schemas';
    88import { createFullAddress } from 'src/utils/create-full-address';
    99import { getQuantityType } from 'src/utils/get-invoice-quantity-type';
     
    179179          <View style={styles.col6}>
    180180            <Text style={[styles.subtitle1, styles.mb4]}>Date Issued</Text>
    181             <Text style={styles.body2}>{fDate(createDate.toDate())}</Text>
     181            <Text style={styles.body2}>{fDate(createDate)}</Text>
    182182          </View>
    183183          <View style={styles.col6}>
    184184            <Text style={[styles.subtitle1, styles.mb4]}>Due date</Text>
    185             <Text style={styles.body2}>{fDate(dueDate.toDate())}</Text>
     185            <Text style={styles.body2}>{fDate(dueDate)}</Text>
    186186          </View>
    187187        </View>
  • src/sections/invoice/invoice-new-edit-address.tsx

    r5d6f37a r057453c  
    77import Typography from '@mui/material/Typography';
    88// hooks
    9 import { useGetSettings } from 'src/api/settings';
     9import { useGetTenant } from 'src/api/tenant';
    1010import { useBoolean } from 'src/hooks/use-boolean';
    1111import { useResponsive } from 'src/hooks/use-responsive';
     
    3232  const { invoiceFrom, invoiceTo } = values;
    3333
    34   const { settings } = useGetSettings();
     34  const { settings: tenant } = useGetTenant();
    3535  const { customers } = useGetCustomers();
    3636
     
    100100      </Stack>
    101101
    102       {settings && (
     102      {tenant && (
    103103        <CompanyListDialog
    104104          title="Companies"
     
    106106          onClose={from.onFalse}
    107107          selected={(selectedId: string) => invoiceFrom?.id === selectedId}
    108           onSelect={(company) => setValue('invoiceFrom', company)}
    109           list={[settings?.company, settings?.['company-ee']]}
     108          onSelect={(tenant) => setValue('invoiceFrom', tenant)}
     109          tenant={tenant}
    110110          action={
    111111            <Button
  • src/sections/invoice/invoice-new-edit-details.tsx

    r5d6f37a r057453c  
    1414import { fCurrency } from 'src/utils/format-number';
    1515// types
    16 import { InvoiceItem } from 'mvpmasters-shared';
     16import { InvoiceItem } from 'src/schemas';
    1717// components
    1818import Iconify from 'src/components/iconify';
     
    7575  const handleSelectService = useCallback(
    7676    (index: number, option: string) => {
    77       setValue(
    78         `items[${index}].price`,
    79         invoiceServices.find((service) => service.id === option)?.price?.[
    80           values.quantityType?.toLowerCase() as 'sprint' | 'hour' | 'month'
    81         ]
    82       );
    83       setValue(
    84         `items[${index}].total`,
    85         values.items.map((item: InvoiceItem) => item.quantity * item.price)[index]
    86       );
     77      const service = invoiceServices.find((service) => service.id === option);
     78      if (!service) return;
     79
     80      const quantityType = values.quantityType?.toLowerCase();
     81      let price = 0;
     82
     83      switch (quantityType) {
     84        case 'sprint':
     85          price = service.sprint;
     86          break;
     87        case 'hour':
     88          price = service.hour;
     89          break;
     90        case 'month':
     91          price = service.month;
     92          break;
     93        default:
     94          price = 0;
     95      }
     96
     97      setValue(`items[${index}].price`, price);
     98      setValue(`items[${index}].total`, values.items[index].quantity * price);
    8799    },
    88100    [setValue, values.items, values.quantityType, invoiceServices]
  • src/sections/invoice/invoice-new-edit-form.tsx

    r5d6f37a r057453c  
    1111import { useRouter } from 'src/routes/hooks';
    1212// types
    13 import { Invoice } from 'mvpmasters-shared';
     13import { CreateInvoice, Invoice } from 'src/schemas';
    1414// hooks
    1515import { useBoolean } from 'src/hooks/use-boolean';
     
    2020import uploadToFirebaseStorage from 'src/utils/upload-to-firebase-storage';
    2121import { pdf } from '@react-pdf/renderer';
    22 import { useGetSettings } from 'src/api/settings';
    23 import {
    24   collections,
    25   documents,
    26   firestoreBatch,
    27   generateId,
    28   updateDocument,
    29 } from 'src/lib/firestore';
     22import { useGetTenant } from 'src/api/tenant';
     23import { collections, generateId, updateDocument } from 'src/lib/firestore';
    3024import { useGetServices } from 'src/api/service';
    3125import { mutate } from 'swr';
    32 import { Timestamp } from 'firebase/firestore';
    3326import InvoiceNewEditStatusDate from './invoice-new-edit-status-date';
    3427import InvoiceNewEditAddress from './invoice-new-edit-address';
    3528import InvoiceNewEditDetails from './invoice-new-edit-details';
    3629import InvoicePDF from './invoice-pdf';
     30import { createInvoice, updateInvoice } from 'src/api/invoice';
    3731
    3832// ----------------------------------------------------------------------
     
    5852];
    5953
     54interface InvoiceItem {
     55  service: string | null;
     56  title: string;
     57  price: number;
     58  total: number;
     59  quantity: number;
     60  description: string;
     61}
     62
    6063export default function InvoiceNewEditForm({ isCopy, currentInvoice }: Props) {
    6164  const router = useRouter();
     
    6972    description: Yup.string().required('Description is required'),
    7073    service: Yup.string().nullable(),
    71     quantity: Yup.number().required('Quantity is required').min(0.5, 'Quantity must be at least 1'),
     74    quantity: Yup.number()
     75      .required('Quantity is required')
     76      .min(0.5, 'Quantity must be at least 0.5'),
    7277    price: Yup.number().required('Price is required').min(0, 'Price must be at least 0'),
    7378    total: Yup.number().required('Total is required').min(0, 'Total must be at least 0'),
     
    9196      .required('Quantity type is required'),
    9297    month: Yup.string().oneOf(monthNames).required('Month is required'),
    93     status: Yup.string().required(),
     98    status: Yup.string().oneOf(['draft', 'processing', 'pending', 'overdue', 'paid']).required(),
    9499    totalAmount: Yup.number().required(),
    95100    // not required
     
    103108
    104109  const { services: invoiceServices } = useGetServices();
    105   const { settings, settingsEmpty, settingsLoading } = useGetSettings();
     110  console.log('invoiceServices', invoiceServices);
     111  const { settings: tenant, settingsEmpty, settingsLoading } = useGetTenant();
    106112
    107113  const defaultValues = useMemo(
     
    110116        !isCopy && currentInvoice?.invoiceNumber
    111117          ? currentInvoice?.invoiceNumber
    112           : incrementInvoiceNumber(settings?.invoice?.lastInvoiceNumber),
    113       createDate: currentInvoice?.createDate?.toDate() || new Date(),
    114       dueDate: currentInvoice?.dueDate?.toDate() || null,
     118          : incrementInvoiceNumber(tenant?.lastInvoiceNumber),
     119      createDate: currentInvoice?.createDate ? new Date(currentInvoice.createDate) : new Date(),
     120      dueDate: currentInvoice?.dueDate
     121        ? new Date(currentInvoice.dueDate)
     122        : new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
    115123      invoiceFrom: currentInvoice?.invoiceFrom || null,
    116124      invoiceTo: currentInvoice?.invoiceTo || null,
     
    138146      totalAmount: currentInvoice?.totalAmount || 0,
    139147    }),
    140     [currentInvoice, isCopy, settings]
     148    [currentInvoice, isCopy, tenant]
    141149  );
    142150
     
    164172
    165173    try {
    166       // generate collection id
    167174      const id = generateId(collections.invoice);
     175
     176      // Ensure dates are valid Date objects
     177      const createDate =
     178        data.createDate instanceof Date ? data.createDate : new Date(data.createDate);
     179      const dueDate = data.dueDate instanceof Date ? data.dueDate : new Date(data.dueDate);
     180
     181      const currentTime = new Date();
     182      createDate.setHours(
     183        currentTime.getHours(),
     184        currentTime.getMinutes(),
     185        currentTime.getSeconds()
     186      );
    168187
    169188      // attach serivce details
     
    173192      }));
    174193
    175       const currentTime = new Date();
    176       const createDateWithCurrentTime = new Date(data.createDate); // This creates a date object using the date from data.createDate
    177       // Set the time of createDateWithCurrentTime to the current hour, minutes, and seconds
    178       createDateWithCurrentTime.setHours(
    179         currentTime.getHours(),
    180         currentTime.getMinutes(),
    181         currentTime.getSeconds()
    182       );
    183 
    184194      // transform data
    185       const writeData = {
     195      const writeData: CreateInvoice = {
    186196        ...data,
    187         invoiceNumber: incrementInvoiceNumber(settings?.invoice.lastInvoiceNumber),
     197        invoiceNumber: incrementInvoiceNumber(tenant?.lastInvoiceNumber),
    188198        status: 'draft',
    189         createDate: Timestamp.fromDate(createDateWithCurrentTime),
    190         dueDate: Timestamp.fromDate(new Date(data.dueDate)),
    191         items,
     199        createDate,
     200        dueDate,
     201        items: items.filter((item) => item.service !== null) as CreateInvoice['items'],
     202        subTotal: data.totalAmount - (data.taxes || 0) - (data.discount || 0),
     203        month: data.month as Invoice['month'],
     204        invoiceFrom: data.invoiceFrom!,
     205        invoiceTo: data.invoiceTo!,
    192206      };
    193207
     
    199213
    200214      // write to DB
    201       await firestoreBatch([
    202         {
    203           docPath: `${collections.invoice}/${id}`,
    204           type: 'set',
    205           data: {
    206             ...writeData,
    207             pdfRef: storagePath,
    208           },
    209         },
    210         {
    211           docPath: `${collections.settings}/${documents.settingsInvoice}`,
    212           type: 'set',
    213           data: { lastInvoiceNumber: writeData.invoiceNumber },
    214         },
    215       ]);
     215      // await firestoreBatch([
     216      //   {
     217      //     docPath: `${collections.invoice}/${id}`,
     218      //     type: 'set',
     219      //     data: {
     220      //       ...writeData,
     221      //       pdfRef: storagePath,
     222      //     },
     223      //   },
     224      //   {
     225      //     docPath: `${collections.settings}/${documents.settingsInvoice}`,
     226      //     type: 'set',
     227      //     data: { lastInvoiceNumber: writeData.invoiceNumber },
     228      //   },
     229      // ]);
     230
     231      await createInvoice({ ...writeData, pdfRef: storagePath });
    216232
    217233      loadingSave.onFalse();
     
    229245    try {
    230246      if (currentInvoice) {
     247        // Ensure dates are valid Date objects
     248        const createDate =
     249          data.createDate instanceof Date ? data.createDate : new Date(data.createDate);
     250        const dueDate = data.dueDate instanceof Date ? data.dueDate : new Date(data.dueDate);
     251
    231252        // attach serivce details
    232253        const items = data.items.map((item) => ({
     
    238259        const writeData = {
    239260          ...data,
    240           createDate: Timestamp.fromDate(new Date(data.createDate)),
    241           dueDate: Timestamp.fromDate(new Date(data.dueDate)),
     261          createDate,
     262          dueDate,
    242263          items,
     264          invoiceFrom: data.invoiceFrom!,
     265          invoiceTo: data.invoiceTo!,
    243266        };
    244267
     
    250273
    251274        // update DB
    252         await updateDocument(collections.invoice, currentInvoice.id, {
     275        // await updateDocument(collections.invoice, currentInvoice.id, {
     276        //   ...writeData,
     277        //   pdfRef: storagePath,
     278        // });
     279
     280        await updateInvoice(currentInvoice.id, {
    253281          ...writeData,
    254282          pdfRef: storagePath,
     283          status: data.status as 'draft' | 'processing' | 'pending' | 'overdue' | 'paid',
     284          month: data.month as
     285            | 'January'
     286            | 'February'
     287            | 'March'
     288            | 'April'
     289            | 'May'
     290            | 'June'
     291            | 'July'
     292            | 'August'
     293            | 'September'
     294            | 'October'
     295            | 'November'
     296            | 'December',
     297          items: items.filter((item) => item.service !== null) as {
     298            service: { id: string; month: number; name: string; sprint: number; hour: number };
     299            title: string;
     300            price: number;
     301            total: number;
     302            quantity: number;
     303            description: string;
     304          }[],
    255305        });
    256306
    257307        // mutate current data
    258         mutate([collections.invoice, currentInvoice.id]);
     308        // mutate([collections.invoice, currentInvoice.id]);
    259309      } else {
    260310        // generate collection id
    261311        const id = generateId(collections.invoice);
     312
     313        // Ensure dates are valid Date objects
     314        const createDate =
     315          data.createDate instanceof Date ? data.createDate : new Date(data.createDate);
     316        const dueDate = data.dueDate instanceof Date ? data.dueDate : new Date(data.dueDate);
    262317
    263318        // attach serivce details
     
    270325        const writeData = {
    271326          ...data,
    272           createDate: Timestamp.fromDate(new Date(data.createDate)),
    273           dueDate: Timestamp.fromDate(new Date(data.dueDate)),
     327          createDate,
     328          dueDate,
    274329          items,
     330          invoiceFrom: data.invoiceFrom!,
     331          invoiceTo: data.invoiceTo!,
    275332        };
    276333
     
    282339
    283340        // write to DB
    284         await firestoreBatch([
    285           {
    286             docPath: `${collections.invoice}/${id}`,
    287             type: 'set',
    288             data: {
    289               ...writeData,
    290               pdfRef: storagePath,
    291             },
    292           },
    293           {
    294             docPath: `${collections.settings}/${documents.settingsInvoice}`,
    295             type: 'set',
    296             data: { lastInvoiceNumber: writeData.invoiceNumber },
    297           },
    298         ]);
     341        // await firestoreBatch([
     342        //   {
     343        //     docPath: `${collections.invoice}/${id}`,
     344        //     type: 'set',
     345        //     data: {
     346        //       ...writeData,
     347        //       pdfRef: storagePath,
     348        //     },
     349        //   },
     350        //   {
     351        //     docPath: `${collections.settings}/${documents.settingsInvoice}`,
     352        //     type: 'set',
     353        //     data: { lastInvoiceNumber: writeData.invoiceNumber },
     354        //   },
     355        // ]);
     356        await createInvoice({ ...writeData, pdfRef: storagePath });
    299357
    300358        reset();
     
    314372    <FormProvider methods={methods}>
    315373      <Card>
    316         {settings?.company && <InvoiceNewEditAddress />}
     374        {!!tenant && <InvoiceNewEditAddress />}
    317375
    318376        <InvoiceNewEditStatusDate isCopy={isCopy} />
  • src/sections/invoice/invoice-new-edit-status-date.tsx

    r5d6f37a r057453c  
    77import { RHFSelect, RHFTextField } from 'src/components/hook-form';
    88// api
    9 import { useGetSettings } from 'src/api/settings';
     9// import { useGetTenant } from 'src/api/settings';
    1010// utils
    1111import { incrementInvoiceNumber } from 'src/utils/increment-invoice-number';
     
    3333  const values = watch();
    3434
    35   const { settings } = useGetSettings();
     35  // const { settings } = useGetTenant();
    3636
    3737  return (
  • src/sections/invoice/invoice-pdf.tsx

    r5d6f37a r057453c  
    1 import { Invoice } from 'mvpmasters-shared';
     1import { Invoice } from 'src/schemas';
    22import InvoiceEEPDF from './invoice-ee-pdf';
    33import InvoiceMKPDF from './invoice-mk-pdf';
  • src/sections/invoice/invoice-table-filters-result.tsx

    r5d6f37a r057453c  
    66import Stack, { StackProps } from '@mui/material/Stack';
    77// types
    8 import { InvoiceTableFilters, InvoiceTableFilterValue } from 'mvpmasters-shared';
     8import { InvoiceTableFilters, InvoiceTableFilterValue } from 'src/schemas';
    99// components
    1010import Iconify from 'src/components/iconify';
  • src/sections/invoice/invoice-table-row.tsx

    r5d6f37a r057453c  
    1616import { fNumber } from 'src/utils/format-number';
    1717// types
    18 import { Invoice } from 'mvpmasters-shared';
     18import { Invoice } from 'src/schemas';
    1919// components
    2020import Label from 'src/components/label';
     
    6060  } = row;
    6161
     62  console.log(createDate);
     63
    6264  const confirmSend = useBoolean();
    6365  const confirmDelete = useBoolean();
     
    105107        <TableCell>
    106108          <ListItemText
    107             primary={format(createDate.toDate(), 'dd MMM yyyy')}
    108             secondary={format(createDate.toDate(), 'p')}
     109            primary={format(new Date(createDate), 'dd MMM yyyy')}
     110            secondary={format(new Date(createDate), 'p')}
    109111            primaryTypographyProps={{ typography: 'body2', noWrap: true }}
    110112            secondaryTypographyProps={{
     
    118120        <TableCell>
    119121          <ListItemText
    120             primary={format(dueDate.toDate(), 'dd MMM yyyy')}
    121             secondary={format(dueDate.toDate(), 'p')}
     122            primary={format(new Date(dueDate), 'dd MMM yyyy')}
     123            secondary={format(new Date(dueDate), 'p')}
    122124            primaryTypographyProps={{ typography: 'body2', noWrap: true }}
    123125            secondaryTypographyProps={{
  • src/sections/invoice/invoice-table-toolbar.tsx

    r5d6f37a r057453c  
    77import InputAdornment from '@mui/material/InputAdornment';
    88// types
    9 import { InvoiceTableFilters, InvoiceTableFilterValue } from 'mvpmasters-shared';
     9import { InvoiceTableFilters, InvoiceTableFilterValue } from 'src/schemas';
    1010// components
    1111import Iconify from 'src/components/iconify';
  • src/sections/invoice/invoice-toolbar.tsx

    r5d6f37a r057453c  
    1818import { useBoolean } from 'src/hooks/use-boolean';
    1919// types
    20 import { Invoice } from 'mvpmasters-shared';
     20import { Invoice } from 'src/schemas';
    2121// components
    2222import Iconify from 'src/components/iconify';
  • src/sections/invoice/mail-compose.tsx

    r5d6f37a r057453c  
    1313import Iconify from 'src/components/iconify';
    1414import Editor from 'src/components/editor';
    15 import { Invoice } from 'mvpmasters-shared';
     15import { Invoice } from 'src/schemas';
    1616import FormProvider from 'src/components/hook-form/form-provider';
    1717import { RHFTextField } from 'src/components/hook-form';
  • src/sections/invoice/view/invoice-edit-view.tsx

    r5d6f37a r057453c  
    2323
    2424  const { currentInvoice } = useGetInvoice({ id });
     25  console.log('currentInvoice', currentInvoice);
    2526
    2627  return (
  • src/sections/invoice/view/invoice-list-view.tsx

    r5d6f37a r057453c  
    3636} from 'src/components/table';
    3737// types
    38 import {
    39   Invoice,
    40   InvoiceStatus,
    41   InvoiceTableFilters,
    42   InvoiceTableFilterValue,
    43 } from 'mvpmasters-shared';
     38import { Invoice, InvoiceStatus, InvoiceTableFilters, InvoiceTableFilterValue } from 'src/schemas';
    4439//
    4540import deleteFromFirebaseStorage from 'src/utils/delete-from-firebase-storage';
    4641// fetch
    47 import { useGetInvoices } from 'src/api/invoice';
     42import { useDeleteInvoice, useGetInvoices } from 'src/api/invoice';
    4843import { collections, removeDocument } from 'src/lib/firestore';
    4944import { mutate } from 'swr';
     
    163158  const [filters, setFilters] = useState(defaultFilters);
    164159
    165   const { invoices: tableData } = useGetInvoices({
    166     where: [['createDate', '>=', filters.startDate]],
    167     orderBy: 'createDate',
    168     direction: 'desc',
    169   });
     160  const { invoices: tableData } = useGetInvoices({ startDate: filters.startDate?.toISOString() });
    170161
    171162  const invoiceMutationKey = useMemo(
     
    269260  );
    270261
     262  const { deleteInvoiceMutation } = useDeleteInvoice();
     263
    271264  const handleDeleteRow = useCallback(
    272265    async (invoice: Invoice) => {
     
    275268        orderBy: 'createDate',
    276269        direction: 'desc',
    277       }); // Get the same params as used in useGetInvoices
    278 
    279       // Optimistically update the cache before the deletion
    280       // mutate(
    281       //   [collections.invoice, serializedParams],
    282       //   (invoices: Invoice[] = []) => invoices.filter((row) => row.id !== invoice.id),
    283       //   false
    284       // );
    285 
    286       await removeDocument(collections.invoice, invoice.id);
     270      });
     271
     272      await deleteInvoiceMutation(invoice.id);
    287273      await deleteFromFirebaseStorage(
    288274        `invoices/${invoice.invoiceTo.name}/${invoice.id}-${invoice.invoiceNumber}.pdf`
    289275      );
    290276
    291       // Optionally, rollback optimistic update or refetch data
    292277      mutate(invoiceMutationKey);
    293278    },
     
    672657      inputData = inputData.filter(
    673658        (invoice) =>
    674           fTimestamp(invoice.createDate.toMillis()) >= fTimestamp(startDate) &&
    675           fTimestamp(invoice.createDate.toMillis()) <= fTimestamp(endDate)
     659          fTimestamp(invoice.createDate.getTime()) >= fTimestamp(startDate.getTime()) &&
     660          fTimestamp(invoice.createDate.getTime()) <= fTimestamp(endDate.getTime())
    676661      );
    677662    }
Note: See TracChangeset for help on using the changeset viewer.