Example #1
0
class WorkOrderQuoteItemStep(SaleQuoteItemStep):
    """Third step for work order pre-sales

    Just like :class:`stoqlib.gui.wizards.salequotewizard.SaleQuoteItemStep`,
    but each item added here will be added to a workorder too (selected
    on a combo).
    """

    #
    #  Public API
    #

    def get_extra_columns(self):
        """Get some extra columns for the items list

        Subclasses can override this and add some extra columns. Those
        columns will be added just after the 'description' and before
        the 'quantity' columns.
        """
        return [Column('_equipment', title=_(u'Equipment'), data_type=str,
                       ellipsize=pango.ELLIPSIZE_END)]

    def setup_work_order(self, work_order):
        """Do some extra setup for the work order

        This is called at the initialization of this step. Subclasses can
        override this to do any extra setup they need on the work order.

        :param work_order: the |workorder| we are describing
        """

    #
    #  SaleQuoteItemStep
    #

    def setup_proxies(self):
        self._radio_group = None
        self._setup_work_orders_widgets()
        super(WorkOrderQuoteItemStep, self).setup_proxies()

    def get_order_item(self, sellable, price, quantity, batch=None):
        item = super(WorkOrderQuoteItemStep, self).get_order_item(
            sellable, price, quantity, batch=batch)

        work_order = self._selected_workorder
        wo_item = work_order.add_sellable(
            sellable, price=price, batch=batch, quantity=quantity)
        wo_item.sale_item = item
        item._equipment = work_order.description

        return item

    def get_saved_items(self):
        for item in super(WorkOrderQuoteItemStep, self).get_saved_items():
            wo_item = WorkOrderItem.get_from_sale_item(self.store, item)
            item._equipment = wo_item.order.description
            yield item

    def remove_items(self, items):
        # Remove the workorder items first to avoid reference problems
        for item in items:
            wo_item = WorkOrderItem.get_from_sale_item(self.store, item)
            wo_item.order.remove_item(wo_item)

        super(WorkOrderQuoteItemStep, self).remove_items(items)

    def get_columns(self):
        columns = [
            Column('sellable.code', title=_(u'Code'),
                   data_type=str, visible=False),
            Column('sellable.barcode', title=_(u'Barcode'),
                   data_type=str, visible=False),
            Column('sellable.description', title=_('Description'),
                   data_type=str, expand=True,
                   format_func=self._format_description, format_func_data=True),
        ]
        columns.extend(self.get_extra_columns())
        columns.extend([
            Column('quantity', title=_(u'Quantity'),
                   data_type=decimal.Decimal, format_func=format_quantity),
            Column('base_price', title=_('Original Price'), data_type=currency),
            Column('price', title=_('Sale Price'), data_type=currency),
            Column('sale_discount', title=_('Discount'),
                   data_type=decimal.Decimal,
                   format_func=get_formatted_percentage),
            Column('total', title=_(u'Total'),
                   data_type=currency),
        ])
        return columns

    def validate_step(self):
        # When finishing the wizard, make sure that all modifications on
        # sale items on this step are propagated to their work order items
        for sale_item in self.model.get_items():
            wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item)
            wo_item.quantity = sale_item.quantity
            wo_item.quantity_decreased = sale_item.quantity_decreased
            wo_item.price = sale_item.price

        return super(WorkOrderQuoteItemStep, self).validate_step()

    #
    #  Private
    #

    def _format_description(self, item, data):
        return format_sellable_description(item.sellable, item.batch)

    def _setup_work_orders_widgets(self):
        self._work_orders_hbox = gtk.HBox(spacing=6)
        self.item_vbox.pack_start(self._work_orders_hbox, False, True, 6)
        self.item_vbox.reorder_child(self._work_orders_hbox, 0)
        self._work_orders_hbox.show()

        label = gtk.Label(_("Work order:"))
        self._work_orders_hbox.pack_start(label, False, True)

        data = []
        for wo in self.wizard.workorders:
            # The work order might be already approved if we are editing a sale
            if wo.can_approve():
                wo.approve()

            self.setup_work_order(wo)
            data.append([wo.description, wo])

        if len(data) <= _MAX_WORK_ORDERS_FOR_RADIO:
            self.work_orders_combo = None
            for desc, wo in data:
                self._add_work_order_radio(desc, wo)
        else:
            self.work_orders_combo = ProxyComboBox()
            self.work_orders_combo.prefill(data)
            self._selected_workorder = self.work_orders_combo.get_selected()
            self._work_orders_hbox.pack_start(self.work_orders_combo,
                                              False, False)

        self._work_orders_hbox.show_all()

    def _add_work_order_radio(self, desc, workorder):
        radio = gtk.RadioButton(group=self._radio_group, label=desc)
        radio.set_data('workorder', workorder)
        radio.connect('toggled', self._on_work_order_radio__toggled)

        if self._radio_group is None:
            self._radio_group = radio
            self._selected_workorder = workorder

        self._work_orders_hbox.pack_start(radio, False, False, 6)
        radio.show_all()

    #
    #  Callbacks
    #

    def on_work_orders_combo__content_changed(self, combo):
        self._selected_workorder = combo.get_selected()

    def _on_work_order_radio__toggled(self, radio):
        if not radio.get_active():
            return
        self._selected_workorder = radio.get_data('workorder')
Example #2
0
class WorkOrderQuoteItemStep(SaleQuoteItemStep):
    """Third step for work order pre-sales

    Just like :class:`stoqlib.gui.wizards.salequotewizard.SaleQuoteItemStep`,
    but each item added here will be added to a workorder too (selected
    on a combo).
    """

    #
    #  Public API
    #

    def get_extra_columns(self):
        """Get some extra columns for the items list

        Subclasses can override this and add some extra columns. Those
        columns will be added just after the 'description' and before
        the 'quantity' columns.
        """
        return [
            Column('_equipment',
                   title=_(u'Equipment'),
                   data_type=str,
                   ellipsize=Pango.EllipsizeMode.END)
        ]

    def setup_work_order(self, work_order):
        """Do some extra setup for the work order

        This is called at the initialization of this step. Subclasses can
        override this to do any extra setup they need on the work order.

        :param work_order: the |workorder| we are describing
        """

    #
    #  SaleQuoteItemStep
    #

    def setup_proxies(self):
        self._radio_group = None
        self._setup_work_orders_widgets()
        super(WorkOrderQuoteItemStep, self).setup_proxies()

    def get_order_item(self,
                       sellable,
                       price,
                       quantity,
                       batch=None,
                       parent=None):
        item = super(WorkOrderQuoteItemStep,
                     self).get_order_item(sellable,
                                          price,
                                          quantity,
                                          batch=batch,
                                          parent=parent)

        work_order = self._selected_workorder
        wo_item = work_order.add_sellable(sellable,
                                          price=price,
                                          batch=batch,
                                          quantity=quantity)
        wo_item.sale_item = item
        item._equipment = work_order.description

        return item

    def get_saved_items(self):
        for item in super(WorkOrderQuoteItemStep, self).get_saved_items():
            wo_item = WorkOrderItem.get_from_sale_item(self.store, item)
            item._equipment = wo_item.order.description
            yield item

    def remove_items(self, items):
        # Remove the workorder items first to avoid reference problems
        for item in items:
            wo_item = WorkOrderItem.get_from_sale_item(self.store, item)
            # If the item's quantity_decreased changed in this step, the
            # synchronization between the 2 that happens on self.validate_step
            # would not have happened yet, meaning that order.remove_item
            # would try to return a wrong quantity to the stock. Force the
            # synchronization to avoid any problems like that
            wo_item.quantity_decreased = item.quantity_decreased
            wo_item.order.remove_item(wo_item)

        super(WorkOrderQuoteItemStep, self).remove_items(items)

    def get_columns(self):
        columns = [
            Column('sellable.code',
                   title=_(u'Code'),
                   data_type=str,
                   visible=False),
            Column('sellable.barcode',
                   title=_(u'Barcode'),
                   data_type=str,
                   visible=False),
            Column('sellable.description',
                   title=_('Description'),
                   data_type=str,
                   expand=True,
                   format_func=self._format_description,
                   format_func_data=True),
        ]
        columns.extend(self.get_extra_columns())
        columns.extend([
            Column('quantity',
                   title=_(u'Quantity'),
                   data_type=decimal.Decimal,
                   format_func=format_quantity),
            Column('base_price', title=_('Original Price'),
                   data_type=currency),
            Column('price', title=_('Sale Price'), data_type=currency),
            Column('sale_discount',
                   title=_('Discount'),
                   data_type=decimal.Decimal,
                   format_func=get_formatted_percentage),
            Column('total', title=_(u'Total'), data_type=currency),
        ])
        return columns

    def validate_step(self):
        # When finishing the wizard, make sure that all modifications on
        # sale items on this step are propagated to their work order items
        for sale_item in self.model.get_items():
            wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item)
            wo_item.quantity = sale_item.quantity
            wo_item.quantity_decreased = sale_item.quantity_decreased
            wo_item.price = sale_item.price

        return super(WorkOrderQuoteItemStep, self).validate_step()

    #
    #  Private
    #

    def _format_description(self, item, data):
        return format_sellable_description(item.sellable, item.batch)

    def _setup_work_orders_widgets(self):
        self._work_orders_hbox = Gtk.HBox(spacing=6)
        self.item_vbox.pack_start(self._work_orders_hbox, False, True, 6)
        self.item_vbox.reorder_child(self._work_orders_hbox, 0)
        self._work_orders_hbox.show()

        label = Gtk.Label(label=_("Work order:"))
        self._work_orders_hbox.pack_start(label, False, True, 0)

        data = []
        for wo in self.wizard.workorders:
            # The work order might be already approved if we are editing a sale
            if wo.can_approve():
                wo.approve()

            self.setup_work_order(wo)
            data.append([wo.description, wo])

        if len(data) <= _MAX_WORK_ORDERS_FOR_RADIO:
            self.work_orders_combo = None
            for desc, wo in data:
                self._add_work_order_radio(desc, wo)
        else:
            self.work_orders_combo = ProxyComboBox()
            self.work_orders_combo.prefill(data)
            self._selected_workorder = self.work_orders_combo.get_selected()
            self._work_orders_hbox.pack_start(self.work_orders_combo, False,
                                              False, 0)

        self._work_orders_hbox.show_all()

    def _add_work_order_radio(self, desc, workorder):
        radio = Gtk.RadioButton(group=self._radio_group, label=desc)
        radio._workorder = workorder
        radio.connect('toggled', self._on_work_order_radio__toggled)

        if self._radio_group is None:
            self._radio_group = radio
            self._selected_workorder = workorder

        self._work_orders_hbox.pack_start(radio, False, False, 6)
        radio.show_all()

    #
    #  Callbacks
    #

    def on_work_orders_combo__content_changed(self, combo):
        self._selected_workorder = combo.get_selected()

    def _on_work_order_radio__toggled(self, radio):
        if not radio.get_active():
            return
        self._selected_workorder = radio._workorder
Example #3
0
class ChartDialog(gtk.Window):
    def __init__(self):
        self._js_data = None
        self._js_options = None
        self._current = None

        gtk.Window.__init__(self)
        self.set_size_request(800, 480)

        self.vbox = gtk.VBox()
        self.add(self.vbox)
        self.vbox.show()

        hbox = gtk.HBox()
        self.vbox.pack_start(hbox, False, False, 6)
        hbox.show()

        label = gtk.Label('Period:')
        hbox.pack_start(label, False, False, 6)
        label.show()

        self.chart_type = ProxyComboBox()
        self.chart_type.connect(
            'content-changed',
            self._on_chart_type__content_changed)
        hbox.pack_start(self.chart_type, False, False, 6)
        self.chart_type.show()

        self.period_values = ProxyComboBox()
        self.period_values.connect(
            'content-changed',
            self._on_period_values__content_changed)
        hbox.pack_start(self.period_values, False, False, 6)
        self.period_values.show()

        self._view = WebView()
        self._view.get_view().connect(
            'load-finished',
            self._on_view__document_load_finished)
        self.vbox.pack_start(self._view, True, True)

        self.results = ObjectList()
        self.results.connect(
            'row-activated',
            self._on_results__row_activated)
        self.vbox.pack_start(self.results, True, True)

        self._setup_daemon()

    @api.async
    def _setup_daemon(self):
        daemon = yield start_daemon()
        self._daemon_uri = daemon.base_uri

        proxy = daemon.get_client()
        yield proxy.callRemote('start_webservice')

        self.chart_type.prefill([
            ('Year', 'YearlyPayments'),
            ('Month', 'MonthlyPayments'),
            ('Day', 'DailyPayments'),
        ])

    @api.async
    def _invoke_chart(self, chart_type_name, **report_kwargs):
        def _get_chart_url(**kwargs):
            params = []
            for key, value in kwargs.items():
                params.append(key + '=' + str(value))
            return '%s/web/chart.json?%s' % (
                self._daemon_uri, '&'.join(params))

        url = _get_chart_url(type=chart_type_name, **report_kwargs)
        page = yield getPage(url)
        data = json.loads(page)
        api.asyncReturn(data)

    def _render_chart(self, chart_class, response):
        self._render_javascript(chart_class, response)
        self._render_objectlist(chart_class, response)

    def _render_javascript(self, chart_class, response):
        ticks = [item['short_title'] for item in response['items']]

        self._js_data = response['data']

        options = {}
        options['description'] = response['description']
        options['series'] = [dict(label=c['title']) for c in chart_class.columns][1:]
        options['xaxis_ticks'] = ticks
        self._js_options = options

        self._view.load_uri('%s/web/static/chart.html' % (
                            self._daemon_uri,))

    def _render_objectlist(self, chart_class, response):
        columns = []
        for kwargs in chart_class.columns:
            kwargs = kwargs.copy()
            name = kwargs.pop('name')
            columns.append(Column(name, **kwargs))
        self.results.set_columns(columns)

        items = []
        for item in response['items']:
            settable = Settable(**item)
            settable.chart_class = chart_class
            items.append(settable)
        self.results.add_list(items, clear=True)
        self.results.show()

    def _load_finished(self):
        self._view.js_function_call(
            "plot", self._js_data, self._js_options)

    @api.async
    def _show_one(self, chart_type_name, start, end):
        chart_class = get_chart_class(chart_type_name)
        report_kwargs = dict(start=start.strftime('%Y-%m-%d'),
                             end=end.strftime('%Y-%m-%d'))

        # Get chart datab
        response = yield self._invoke_chart(chart_type_name, **report_kwargs)
        self._render_chart(chart_class, response)

    def _update_period_values(self):
        chart_type_name = self.chart_type.get_selected()
        chart_class = get_chart_class(chart_type_name)
        values = chart_class.get_combo_labels()
        self.period_values.prefill(values)

    #
    # Callbacks
    #

    def _on_view__document_load_finished(self, view, frame):
        self._load_finished()

    def _on_chart_type__content_changed(self, combo):
        self._update_period_values()

    def _on_period_values__content_changed(self, combo):
        kind = self.chart_type.get_selected()
        value = self.period_values.get_selected()
        if not value:
            return
        start, end = value
        if self._current == (kind, start, end):
            return
        self._show_one(kind, start, end)
        self._current = kind, start, end

    def _on_results__row_activated(self, results, item):
        chart_type_name = item.chart_class.__name__
        if chart_type_name == 'YearlyPayments':
            start = localdate(item.year, 1, 1).date()
            end = localdate(item.year, 12, 31).date()
            chart_type_name = 'MonthlyPayments'
        elif chart_type_name == 'MonthlyPayments':
            start = localdate(item.year, item.month, 1).date()
            end = start + relativedelta(days=31)
            chart_type_name = 'DailyPayments'
        else:
            return
        self._show_one(chart_type_name, start, end)
Example #4
0
class ChartDialog(gtk.Window):
    def __init__(self):
        self._js_data = None
        self._js_options = None
        self._current = None

        gtk.Window.__init__(self)
        self.set_size_request(800, 480)

        self.vbox = gtk.VBox()
        self.add(self.vbox)
        self.vbox.show()

        hbox = gtk.HBox()
        self.vbox.pack_start(hbox, False, False, 6)
        hbox.show()

        label = gtk.Label('Period:')
        hbox.pack_start(label, False, False, 6)
        label.show()

        self.chart_type = ProxyComboBox()
        self.chart_type.connect('content-changed',
                                self._on_chart_type__content_changed)
        hbox.pack_start(self.chart_type, False, False, 6)
        self.chart_type.show()

        self.period_values = ProxyComboBox()
        self.period_values.connect('content-changed',
                                   self._on_period_values__content_changed)
        hbox.pack_start(self.period_values, False, False, 6)
        self.period_values.show()

        self._view = WebView()
        self._view.get_view().connect('load-finished',
                                      self._on_view__document_load_finished)
        self.vbox.pack_start(self._view, True, True)

        self.results = ObjectList()
        self.results.connect('row-activated', self._on_results__row_activated)
        self.vbox.pack_start(self.results, True, True)

        self._setup_daemon()

    @api. async
    def _setup_daemon(self):
        daemon = yield start_daemon()
        self._daemon_uri = daemon.base_uri

        proxy = daemon.get_client()
        yield proxy.callRemote('start_webservice')

        self.chart_type.prefill([
            ('Year', 'YearlyPayments'),
            ('Month', 'MonthlyPayments'),
            ('Day', 'DailyPayments'),
        ])

    @api. async
    def _invoke_chart(self, chart_type_name, **report_kwargs):
        def _get_chart_url(**kwargs):
            params = []
            for key, value in kwargs.items():
                params.append(key + '=' + str(value))
            return '%s/web/chart.json?%s' % (self._daemon_uri,
                                             '&'.join(params))

        url = _get_chart_url(type=chart_type_name, **report_kwargs)
        page = yield getPage(url)
        data = json.loads(page)
        api.asyncReturn(data)

    def _render_chart(self, chart_class, response):
        self._render_javascript(chart_class, response)
        self._render_objectlist(chart_class, response)

    def _render_javascript(self, chart_class, response):
        ticks = [item['short_title'] for item in response['items']]

        self._js_data = response['data']

        options = {}
        options['description'] = response['description']
        options['series'] = [
            dict(label=c['title']) for c in chart_class.columns
        ][1:]
        options['xaxis_ticks'] = ticks
        self._js_options = options

        self._view.load_uri('%s/web/static/chart.html' % (self._daemon_uri, ))

    def _render_objectlist(self, chart_class, response):
        columns = []
        for kwargs in chart_class.columns:
            kwargs = kwargs.copy()
            name = kwargs.pop('name')
            columns.append(Column(name, **kwargs))
        self.results.set_columns(columns)

        items = []
        for item in response['items']:
            settable = Settable(**item)
            settable.chart_class = chart_class
            items.append(settable)
        self.results.add_list(items, clear=True)
        self.results.show()

    def _load_finished(self):
        self._view.js_function_call("plot", self._js_data, self._js_options)

    @api. async
    def _show_one(self, chart_type_name, start, end):
        chart_class = get_chart_class(chart_type_name)
        report_kwargs = dict(start=start.strftime('%Y-%m-%d'),
                             end=end.strftime('%Y-%m-%d'))

        # Get chart datab
        response = yield self._invoke_chart(chart_type_name, **report_kwargs)
        self._render_chart(chart_class, response)

    def _update_period_values(self):
        chart_type_name = self.chart_type.get_selected()
        chart_class = get_chart_class(chart_type_name)
        values = chart_class.get_combo_labels()
        self.period_values.prefill(values)

    #
    # Callbacks
    #

    def _on_view__document_load_finished(self, view, frame):
        self._load_finished()

    def _on_chart_type__content_changed(self, combo):
        self._update_period_values()

    def _on_period_values__content_changed(self, combo):
        kind = self.chart_type.get_selected()
        value = self.period_values.get_selected()
        if not value:
            return
        start, end = value
        if self._current == (kind, start, end):
            return
        self._show_one(kind, start, end)
        self._current = kind, start, end

    def _on_results__row_activated(self, results, item):
        chart_type_name = item.chart_class.__name__
        if chart_type_name == 'YearlyPayments':
            start = localdate(item.year, 1, 1).date()
            end = localdate(item.year, 12, 31).date()
            chart_type_name = 'MonthlyPayments'
        elif chart_type_name == 'MonthlyPayments':
            start = localdate(item.year, item.month, 1).date()
            end = start + relativedelta(days=31)
            chart_type_name = 'DailyPayments'
        else:
            return
        self._show_one(chart_type_name, start, end)