Пример #1
0
class PaymentFlowHistoryDialog(BasicDialog):
    title = _(u'Payment Flow History Dialog')
    desc = _("Select a date or a range to be visualised in the report:")
    size = (-1, -1)
    model_type = PaymentFlowDay

    def __init__(self, store):
        """A dialog to print the PaymentFlowHistoryReport report.

        :param store: a store
        """
        self.store = store
        BasicDialog.__init__(self,
                             header_text='<b>%s</b>' % self.desc,
                             title=self.title)
        self._setup_widgets()

    #
    # BasicDialog
    #

    def confirm(self):
        state = self._date_filter.get_state()
        from stoqlib.database.queryexecuter import DateQueryState
        if isinstance(state, DateQueryState):
            start, end = state.date, state.date
        else:
            start, end = state.start, state.end

        results = PaymentFlowDay.get_flow_history(self.store, start, end)
        if not results:
            info(_('No payment history found.'))
            return False

        print_report(PaymentFlowHistoryReport, payment_histories=results)
        return True

    #
    # Private
    #

    def _setup_widgets(self):
        self.ok_button.set_label(gtk.STOCK_PRINT)

        self._date_filter = DateSearchFilter(_(u'Date:'))
        # FIXME: add a remove_option method in DateSearchFilter.
        self._date_filter.clear_options()
        self._date_filter.add_custom_options()
        for option in [Today, Yesterday, LastWeek, LastMonth]:
            self._date_filter.add_option(option)
        self._date_filter.select(position=0)

        self.vbox.pack_start(self._date_filter, False, False)
        self._date_filter.show_all()
Пример #2
0
class PaymentFlowHistoryDialog(BasicDialog):
    title = _(u'Payment Flow History Dialog')
    desc = _("Select a date or a range to be visualised in the report:")
    size = (-1, -1)
    model_type = PaymentFlowDay

    def __init__(self, store):
        """A dialog to print the PaymentFlowHistoryReport report.

        :param store: a store
        """
        self.store = store
        BasicDialog.__init__(self, header_text='<b>%s</b>' % self.desc,
                             title=self.title)
        self._setup_widgets()

    #
    # BasicDialog
    #

    def confirm(self):
        state = self._date_filter.get_state()
        from stoqlib.database.queryexecuter import DateQueryState
        if isinstance(state, DateQueryState):
            start, end = state.date, state.date
        else:
            start, end = state.start, state.end

        results = PaymentFlowDay.get_flow_history(self.store, start, end)
        if not results:
            info(_('No payment history found.'))
            return False

        print_report(PaymentFlowHistoryReport, payment_histories=results)
        return True

    #
    # Private
    #

    def _setup_widgets(self):
        self.ok_button.set_label(gtk.STOCK_PRINT)

        self._date_filter = DateSearchFilter(_(u'Date:'))
        # FIXME: add a remove_option method in DateSearchFilter.
        self._date_filter.clear_options()
        self._date_filter.add_custom_options()
        for option in [Today, Yesterday, LastWeek, LastMonth]:
            self._date_filter.add_option(option)
        self._date_filter.select(position=0)

        self.vbox.pack_start(self._date_filter, False, False)
        self._date_filter.show_all()
Пример #3
0
class DateRangeDialog(BasicDialog):
    """A simple dialog for selecting a date range

    When confirmed, a :class:`date_range` object will be returned
    containig the information about the date range selected
    """

    title = _(u'Select a date range')
    size = (-1, -1)

    def __init__(self, title=None, header_text=None):
        title = title or self.title
        header_text = '<b>%s</b>' % header_text if header_text else ''
        BasicDialog.__init__(self, title=title, header_text=header_text)

        self._setup_widgets()

    #
    #  BasicDialog
    #

    def confirm(self):
        BasicDialog.confirm(self)

        state = self.date_filter.get_state()
        if isinstance(state, DateQueryState):
            start, end = state.date, state.date
        else:
            start, end = state.start, state.end

        self.retval = date_range(start=start, end=end)

    #
    #  Private
    #

    def _setup_widgets(self):
        self.date_filter = DateSearchFilter(_(u'Date:'))
        # FIXME: add a remove_option method in DateSearchFilter.
        self.date_filter.clear_options()
        self.date_filter.add_custom_options()
        for option in [Today, Yesterday, LastWeek, LastMonth]:
            self.date_filter.add_option(option)
        self.date_filter.select(position=0)

        self.vbox.pack_start(self.date_filter, False, False)
        self.date_filter.show_all()
Пример #4
0
class TillDailyMovementDialog(BaseEditor):
    """Shows informations related to till operations over a daterange.
    It can also be filtered by branch.
    """

    title = _("Daily Movement")
    hide_footer = True
    size = (950, 450)
    model_type = Settable
    gladefile = "TillDailyMovementDialog"
    proxy_widgets = ['branch', 'in_subtotal', 'in_credit', 'in_total',
                     'out_subtotal', 'out_credit', 'out_total']

    #
    #  Private
    #

    def _setup_widgets(self):
        # Branches combo
        items = api.get_branches_for_filter(self.store)
        self.branch.prefill(items)

        # Daterange filter
        self.date_filter = DateSearchFilter(_(u'Date:'))
        self.date_filter.clear_options()
        self.date_filter.add_custom_options()
        for option in [Today, Yesterday, LastWeek, LastMonth]:
            self.date_filter.add_option(option)
        self.date_filter.select(position=0)
        self.daterange_hbox.pack_start(self.date_filter, False, False, 0)
        self.date_filter.show_all()

        # Setting report lists' columns
        self.sales_list.set_columns(self._get_sales_columns())
        self.inpayments_list.set_columns(self._get_lonely_payments_columns())
        self.purchases_list.set_columns(self._get_purchases_columns())
        self.outpayments_list.set_columns(self._get_lonely_payments_columns())
        self.return_sales_list.set_columns(self._get_return_sales_columns())
        self.supplies_list.set_columns(self._get_till_columns())
        self.removals_list.set_columns(self._get_till_columns())
        self.permethod_list.set_columns(self._get_permethod_columns())
        self.percard_list.set_columns(self._get_percard_columns())

        # Print button is insensitive, until the first report is generated
        self.print_button.set_sensitive(False)

        self._setup_summary_labels()

    def _get_sales_columns(self):
        return [IdentifierColumn('identifier', title=_('Sale #'), sorted=True),
                Column('salesperson', title=_('Sales Person'), data_type=str),
                Column('client', title=_('Client'), data_type=str, expand=True),
                Column('branch', title=_('Branch'), data_type=str, visible=False),
                Column('value', title=_('Value'), data_type=str,
                       justify=Gtk.Justification.RIGHT)]

    def _get_lonely_payments_columns(self):
        return [IdentifierColumn('identifier', title=_('Payment #'), sorted=True),
                Column('method', title=_('Method'), data_type=str),
                Column('description', title=_('Description'), expand=True,
                       data_type=str),
                Column('branch', title=_('Branch'), data_type=str, visible=False),
                Column('value', title=_('Payment Value'), data_type=currency)]

    def _get_purchases_columns(self):
        return [IdentifierColumn('identifier', title=_('Code #'), sorted=True),
                Column('status_str', title=_('Status'), data_type=str),
                Column('responsible_name', title=_('Responsible'), expand=True,
                       data_type=str),
                Column('branch_name', title=_('Branch'), data_type=str),
                Column('notes', title=_('Notes'), data_type=str),
                Column('supplier_name', title=_('Supplier'), data_type=str),
                Column('purchase_total', title=_('Value'), data_type=currency)]

    def _get_return_sales_columns(self):
        return [IdentifierColumn('identifier', title=_('Code #'), sorted=True),
                Column('salesperson', title=_('Sales Person'), data_type=str),
                Column('client', title=_('Client'), expand=True, data_type=str),
                Column('return_date', title=_('Return Date'),
                       data_type=datetime.date),
                Column('branch', title=_('Branch'), data_type=str, visible=False),
                Column('value', title=_('Sale Value'), data_type=currency)]

    def _get_till_columns(self):
        return [IdentifierColumn('identifier', title=_('Entry #'), sorted=True),
                Column('description', title=_('Description'), data_type=str,
                       expand=True),
                Column('branch_name', title=_('Branch'), data_type=str, visible=False),
                Column('value', title=_('Value'), data_type=currency)]

    def _get_permethod_columns(self):
        return [Column('method', title=_('Payment Method'), sorted=True,
                       expand=True),
                Column('in_value', title=_('Income Total'), data_type=currency),
                Column('out_value', title=_('Outgoing Total'),
                       data_type=currency)]

    def _get_percard_columns(self):
        return [Column('provider', title=_('Provider Name'), data_type=str,
                       expand=True),
                Column('income', title=_('Income Total'), data_type=currency)]

    def _create_summary_label(self, report, column='value', label=None):
        # Setting tha data
        obj_list = getattr(self, report + '_list')
        box = getattr(self, report + '_vbox')
        if label is None:
            label = _('Total:')
        label = '<b>%s</b>' % api.escape(label)
        value_format = '<b>%s</b>'

        # Creating the label
        label = SummaryLabel(klist=obj_list, column=column, label=label,
                             value_format=value_format)

        # Displaying the label
        box.pack_start(label, False, False, 0)
        label.show()
        return label

    def _setup_summary_labels(self):
        # Supplies
        self.supplies_label = self._create_summary_label('supplies')
        # Removals
        self.removals_label = self._create_summary_label('removals')
        # Percard
        self.percard_label = self._create_summary_label('percard',
                                                        column='income')

    def _update_summary_labels(self):
        self.supplies_label.update_total()
        self.removals_label.update_total()
        self.percard_label.update_total()
        self.proxy.update_many(('in_subtotal', 'in_credit', 'in_total',
                                'out_subtotal', 'out_credit', 'out_total'))

    def _generate_dailymovement_data(self, store):
        query = And(Payment.status.is_in([Payment.STATUS_PENDING,
                                          Payment.STATUS_PAID]),
                    self._get_query(Payment.open_date, Payment.branch))

        # Keys are the sale objects, and values are lists with all payments
        self.sales = collections.OrderedDict()

        # Keys are the returned sale objects, and values are lists with all payments
        self.return_sales = collections.OrderedDict()
        self.purchases = collections.OrderedDict()

        # lonely input and output payments
        self.lonely_in_payments = []
        self.lonely_out_payments = []

        # values are lists with the first element the summary of the input, and
        # the second the summary of the output
        method_summary = {}
        self.card_summary = {}

        result = store.find(DailyInPaymentView, query)
        for p in result.order_by(Sale.identifier, Payment.identifier):
            if p.sale:
                subtotal = p.sale_subtotal
                total = p.sale.get_total_sale_amount(subtotal)
                salesperson = p.salesperson_name or _('Not Specified')
                client = p.client_name or _('Not Specified')
                sale = DailyMovementSale(identifier=p.sale.identifier,
                                         salesperson=salesperson,
                                         client=client,
                                         branch=p.branch_name,
                                         value=get_formatted_price(total))
                sale_payments = self.sales.setdefault(sale,
                                                      collections.OrderedDict())
                details = ''
                method_desc = p.method.get_description()
                if p.check_data:
                    account = p.check_data.bank_account
                    numbers = sorted(
                        payment.payment_number for payment
                        in p.sale.payments if bool(payment.payment_number))
                    # Ensure that the check numbers are ordered
                    parts = []
                    if account.bank_number:
                        parts.append(_(u'Bank: %s') % account.bank_number)
                    if account.bank_branch:
                        parts.append(_(u'Agency: %s') % account.bank_branch)
                    if account.bank_account:
                        parts.append(_(u'Account: %s') % account.bank_account)
                    if numbers:
                        parts.append(_(u'Numbers: %s') % ', '.join(numbers))
                    details = ' / '.join(parts)

                if p.card_data:
                    if p.card_data.card_type == CreditCardData.TYPE_DEBIT:
                        method_desc += ' ' + _('Debit')
                    else:
                        method_desc += ' ' + _(u'Credit')
                    details = '%s - %s - %s' % (p.card_data.auth,
                                                p.card_data.provider.short_name or '',
                                                p.card_data.device.description or '')

                key = (method_desc, details)
                item = sale_payments.setdefault(key, [0, 0])
                item[0] += p.value
                item[1] += 1

            else:
                self.lonely_in_payments.append(p)

            method_summary.setdefault(p.method, [0, 0])
            method_summary[p.method][0] += p.value
            if p.card_data:
                type_desc = p.card_data.short_desc[p.card_data.card_type]
                key = (p.card_data.provider.short_name, type_desc)
                self.card_summary.setdefault(key, 0)
                self.card_summary[key] += p.value

        result = store.find(DailyOutPaymentView, query)
        for p in result.order_by(Payment.identifier):
            if p.purchase:
                purchase_payments = self.purchases.setdefault(p.purchase, [])
                purchase_payments.append(p)
            elif p.sale:
                subtotal = p.sale_subtotal
                value = p.sale.get_total_sale_amount(subtotal)
                salesperson = p.salesperson_name or _('Not Specified')
                client = p.client_name or _('Not Specified')
                sale = DailyMovementSale(identifier=p.sale.identifier,
                                         salesperson=salesperson,
                                         client=client,
                                         return_date=p.sale.return_date,
                                         branch=p.branch_name,
                                         value=value)
                return_sales_payment = self.return_sales.setdefault(sale, [])
                return_sales_payment.append(p)
            else:
                self.lonely_out_payments.append(p)

            method_summary.setdefault(p.method, [0, 0])
            method_summary[p.method][1] += p.value

        self.method_summary = []
        for method, (in_value, out_value) in method_summary.items():
            self.method_summary.append((method,
                                        in_value,
                                        out_value))
        self.method_summary.sort(key=lambda m: _(m[0].description))

        # Till removals
        query = And(Eq(TillEntry.payment_id, None),
                    self._get_query(TillEntry.date, TillEntry.branch),
                    TillEntry.value < 0)
        self.till_removals = store.find(TillEntry, query)

        # Till supply
        query = And(Eq(TillEntry.payment_id, None),
                    self._get_query(TillEntry.date, TillEntry.branch),
                    TillEntry.value > 0)
        self.till_supplies = store.find(TillEntry, query)

    def _show_lonely_payments(self, payments, widget):
        widget.clear()
        for payment in payments:
            payment_data = Settable(identifier=payment.identifier,
                                    method=payment.method.get_description(),
                                    description=payment.description,
                                    branch=payment.branch_name,
                                    value=payment.value)
            widget.append(payment_data)

    def _show_report(self):
        self._generate_dailymovement_data(self.store)

        # Sale data
        self.sales_list.clear()
        for sale, payments in self.sales.items():
            self.sales_list.append(None, sale)
            for details, values in payments.items():
                value = '%s (%sx)' % (get_formatted_price(values[0]), values[1])
                payment_data = Settable(identifier=None,
                                        salesperson=details[0],
                                        client=details[1],
                                        value=value)
                self.sales_list.append(sale, payment_data)

        # Lonely in payments
        self._show_lonely_payments(self.lonely_in_payments,
                                   self.inpayments_list)

        # Purchase data
        self.purchases_list.clear()
        for purchase, payments in self.purchases.items():
            self.purchases_list.append(None, purchase)
            for payment in payments:
                # TODO Add details refering to Bank, Agency later
                payment_data = Settable(identifier=payment.identifier,
                                        notes=payment.method.get_description())
                self.purchases_list.append(purchase, payment_data)

        # Lonely out payments
        self._show_lonely_payments(self.lonely_out_payments,
                                   self.outpayments_list)

        # Return sales
        self.return_sales_list.clear()
        for sale, payments in self.return_sales.items():
            self.return_sales_list.append(None, sale)
            for payment in payments:
                payment_data = Settable(identifier=payment.identifier,
                                        salesperson=payment.method.get_description(),
                                        client=payment.description,
                                        value=get_formatted_price(payment.value))
                self.return_sales_list.append(sale, payment_data)

        # Supplies
        self.supplies_list.clear()
        self.supplies_list.add_list(self.till_supplies)

        # Removals
        self.removals_list.clear()
        self.removals_list.add_list(self.till_removals)

        # Summary's per payment method data
        self.permethod_list.clear()
        self.model.in_subtotal = self.model.out_subtotal = 0
        self.model.in_credit = self.model.out_credit = currency(0)
        for method in self.method_summary:
            method_data = Settable(method=_(method[0].description),
                                   in_value=method[1],
                                   out_value=method[2])
            self.permethod_list.append(method_data)
            self.model.in_subtotal += method[1]
            self.model.out_subtotal += method[2]
            if method[0].method_name == 'credit':
                self.model.in_credit = currency(method[1])
                self.model.out_credit = currency(method[2])

        self.model.in_subtotal = currency(self.model.in_subtotal)
        self.model.out_subtotal = currency(self.model.out_subtotal)
        self.model.in_total = currency(self.model.in_subtotal -
                                       self.model.in_credit)
        self.model.out_total = currency(self.model.out_subtotal -
                                        self.model.out_credit)

        # Summary's per card provider data
        self.percard_list.clear()
        keys = list(self.card_summary.keys())
        for key in sorted(keys):
            card_summary_data = Settable(provider=key[0] + ' ' + key[1],
                                         income=self.card_summary[key])
            self.percard_list.append(card_summary_data)

        self._update_summary_labels()

    def _get_query(self, date_attr, branch_attr):
        daterange = self.get_daterange()
        query = [Date(date_attr) >= Date(daterange[0]),
                 Date(date_attr) <= Date(daterange[1])]

        branch = self.model.branch
        if branch is not None:
            query.append(branch_attr == branch)
        return And(*query)

    #
    # Public API
    #

    def get_daterange(self):
        start = self.date_filter.get_start_date()
        end = self.date_filter.get_end_date()
        return (start, end)

    def set_daterange(self, start, end=None):
        self.date_filter.set_state(start, end)

    #
    # BaseEditor Hooks
    #

    def create_model(self, store):
        return Settable(branch=api.get_current_branch(store),
                        in_total=currency(0), in_credit=currency(0),
                        in_subtotal=currency(0), out_total=currency(0),
                        out_credit=currency(0), out_subtotal=currency(0))

    def setup_proxies(self):
        self._setup_widgets()
        self.proxy = self.add_proxy(self.model, TillDailyMovementDialog.proxy_widgets)

    #
    # Callbacks
    #

    def on_search_button__clicked(self, widget):
        self._show_report()
        self.print_button.set_sensitive(True)

    def on_print_button__clicked(self, widget):
        branch = self.model.branch
        daterange = self.get_daterange()
        print_report(TillDailyMovementReport, self.store, branch, daterange, self)