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')
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
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)
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)