def test_logic(): type = EnumValues.get(DIRECT_PO_TYPE_KEY) status = EnumValues.get(PO_ISSUED_STATUS_KEY) receiving_status = EnumValues.get(RECEIVING_DRAFT_STATUS_KEY) date = object_faker.faker.date_time_this_year() po = object_faker.purchase_order(number_of_line=2, type=type, status=status) db_util.save_objects_commit(po) remark = object_faker.faker.text(max_nb_chars=50) list_expect = [ receiving_status.display, date.strftime("%Y-%m-%d"), remark, po.supplier.name, po.order_date.strftime("%Y-%m-%d"), po.remark ] edit_expect = [ receiving_status.display, date.strftime("%Y-%m-%d"), remark, ] # Crete new receiving self.assertPageRendered( method=self.test_client.post, data=dict(purchase_order=po.id, status=receiving_status.id, create_lines='y', date=date, remark=remark), endpoint=self.create_endpoint(view='receiving'), expect_contents=list_expect) self.assertPageRendered( expect_contents=edit_expect, endpoint=self.edit_endpoint(view='receiving')) # Edit existing receiving new_remark = object_faker.faker.text(max_nb_chars=50) new_receive_date = object_faker.faker.date_time_this_year() complete_status = EnumValues.get(RECEIVING_COMPLETE_STATUS_KEY) new_expected = [ complete_status.display, new_receive_date.strftime("%Y-%m-%d"), new_remark, po.supplier.name, po.order_date.strftime("%Y-%m-%d"), po.remark ] self.assertPageRendered( method=self.test_client.post, endpoint=self.edit_endpoint(view='receiving'), data=dict(date=new_receive_date, status=complete_status.id, remark=new_remark), expect_contents=new_expected) # Detail page self.assertPageRendered( method=self.test_client.get, endpoint=self.details_endpoint(view='receiving'), expect_contents=new_expected)
def test_logic(): fixture.login_as_admin(self.test_client) user, password = object_faker.user(role_names=[ 'franchise_sales_order_create', 'franchise_sales_order_view', 'franchise_sales_order_edit', 'product_view' ]) franchise_so_type = EnumValues.get(FRANCHISE_SO_TYPE_KEY) sales_order = object_faker.sales_order(creator=user, number_of_line=1, type=franchise_so_type) db_util.save_objects_commit(sales_order, user) so_id = sales_order.id shipped_status = EnumValues.get(SO_SHIPPED_STATUS_KEY) fixture.login_user(self.test_client, user.email, password) rv = self.test_client.put('/api/sales_order/' + str(so_id), follow_redirects=True, data=dict(status_id=shipped_status.id)) self.assertIn(b'message', rv.data) self.assertIn(b'Status update successfully', rv.data) self.assertEqual(rv.status_code, 200) so_from_db = Info.get_db().session.query(SalesOrder).get(so_id) self.assertIsNotNone(so_from_db) self.assertEquals(SO_SHIPPED_STATUS_KEY, so_from_db.status.code)
def test_saleable_qty(self): from psi.app.services.purchase_order import PurchaseOrderService with self.test_client: from tests.fixture import login_as_admin login_as_admin(self.test_client) from psi.app.models import EnumValues db = Info.get_db() po = of.purchase_order(number_of_line=1, type=EnumValues.get( const.DIRECT_PO_TYPE_KEY)) recv = PurchaseOrderService.create_receiving_if_not_exist(po) from psi.app.utils import db_util db_util.save_objects_commit(po, recv) recv.status = EnumValues.get(const.RECEIVING_COMPLETE_STATUS_KEY) inv_trans = recv.operate_inv_trans_by_recv_status() new_po = recv.update_purchase_order_status() db_util.save_objects_commit(new_po, inv_trans) self.assertEquals(inv_trans.lines[0].quantity, po.lines[0].quantity) self.assertEquals(inv_trans.lines[0].saleable_quantity, po.lines[0].quantity) self.assertEquals(inv_trans.lines[0].in_transit_quantity, 0) self.assertEqual(inv_trans.date, recv.date) self.assertEqual(inv_trans.lines[0].product, po.lines[0].product) self.assertEquals(inv_trans.lines[0].quantity, recv.lines[0].quantity) self.assertEquals(inv_trans.lines[0].saleable_quantity, recv.lines[0].quantity) self.assertEquals(inv_trans.lines[0].in_transit_quantity, 0) self.assertEqual(inv_trans.date, recv.date) self.assertEqual(inv_trans.lines[0].product, recv.lines[0].product)
def edit_form(self, obj=None): form = super(FranchisePurchaseOrderAdmin, self).edit_form(obj) # Set query_factory for newly added line parent_org_id = obj.to_organization.id # If we uncomment follow line to limit the query to current organization # The AJAX look up fails. # form.lines.form.product.kwargs['query_factory'] = partial( # Product.organization_filter, parent_org_id) if not security_util.user_has_role('purchase_price_view'): form_util.del_form_field(self, form, 'goods_amount') form_util.del_form_field(self, form, 'total_amount') form_util.del_inline_form_field(form.lines.form, form.lines.entries, 'total_amount') form_util.del_inline_form_field(form.lines.form, form.lines.entries, 'unit_price') # Set option list of status available if obj.status.code in [ const.PO_RECEIVED_STATUS_KEY, const.PO_PART_RECEIVED_STATUS_KEY, const.PO_PART_RECEIVED_STATUS_KEY, const.PO_ISSUED_STATUS_KEY, const.PO_DRAFT_STATUS_KEY ]: form.status.query = [ EnumValues.get(obj.status.code), ] if obj.status.code == const.PO_DRAFT_STATUS_KEY: form.status.query.append(EnumValues.get( const.PO_ISSUED_STATUS_KEY)) # Set product query option for old lines(forbid to change product for # existing line) line_entries = form.lines.entries products = Product.organization_filter(parent_org_id).all() for sub_line in line_entries: sub_line.form.product.query = products return form
def edit_form(self, obj=None): form = super(FranchisePurchaseOrderAdmin, self).edit_form(obj) # Set query_factory for newly added line parent_org_id = obj.to_organization.id # If we uncomment follow line to limit the query to current organization # The AJAX look up fails. # form.lines.form.product.kwargs['query_factory'] = partial( # Product.organization_filter, parent_org_id) if not security_util.user_has_role('purchase_price_view'): form_util.del_form_field(self, form, 'goods_amount') form_util.del_form_field(self, form, 'total_amount') form_util.del_inline_form_field(form.lines.form, form.lines.entries, 'total_amount') form_util.del_inline_form_field(form.lines.form, form.lines.entries, 'unit_price') # Set option list of status available if obj.status.code in [const.PO_RECEIVED_STATUS_KEY, const.PO_PART_RECEIVED_STATUS_KEY, const.PO_PART_RECEIVED_STATUS_KEY, const.PO_ISSUED_STATUS_KEY, const.PO_DRAFT_STATUS_KEY]: form.status.query = [EnumValues.get(obj.status.code), ] if obj.status.code == const.PO_DRAFT_STATUS_KEY: form.status.query.append( EnumValues.get(const.PO_ISSUED_STATUS_KEY)) # Set product query option for old lines(forbid to change product for # existing line) line_entries = form.lines.entries products = Product.organization_filter(parent_org_id).all() for sub_line in line_entries: sub_line.form.product.query = products return form
def test_not_allowed_if_not_franchise_organization(self): from psi.app.models import EnumValues, Organization, PurchaseOrder with self.test_client: login_as_admin(self.test_client) org_type = EnumValues.get(const.DIRECT_SELLING_STORE_ORG_TYPE_KEY) organization = object_faker.organization( parent=Organization.query.get(1), type=org_type) user, pwd = object_faker.user(role_names=[ 'franchise_purchase_order_create', 'franchise_purchase_order_edit', 'franchise_purchase_order_delete', 'franchise_purchase_order_view' ], organization=organization) db_util.save_objects_commit(user, organization) login_user(self.test_client, user.email, pwd) draft_status = EnumValues.get(const.PO_DRAFT_STATUS_KEY) order_date = object_faker.faker.date_time_this_year() logistic_amount = random.randint(0, 100) remark = object_faker.faker.text(max_nb_chars=50) rv = self.test_client.post(url_for('fpo.create_view', url=url_for('fpo.index_view')), data=dict( status=draft_status.id, order_date=order_date, logistic_amount=logistic_amount, remark=remark), follow_redirects=True) self.assertEqual(200, rv.status_code) self.assertIn( 'Your organization is not a franchise store and is not allowed to ' 'create franchise purchase order', rv.data) po = PurchaseOrder.query.all() self.assertEqual(0, len(po))
def edit_form(self, obj=None): form = super(DirectPurchaseOrderAdmin, self).edit_form(obj) supplier_id = obj.transient_supplier.id # Set query_factory for newly added line form.lines.form.product.kwargs['query_factory'] = partial( Product.supplier_filter, supplier_id) if not security_util.user_has_role('purchase_price_view'): form_util.del_form_field(self, form, 'goods_amount') form_util.del_form_field(self, form, 'total_amount') form_util.del_inline_form_field(form.lines.form, form.lines.entries, 'unit_price') form_util.del_inline_form_field(form.lines.form, form.lines.entries, 'total_amount') # Set option list of status available if obj.status.code in [ const.PO_RECEIVED_STATUS_KEY, const.PO_PART_RECEIVED_STATUS_KEY, const.PO_PART_RECEIVED_STATUS_KEY, const.PO_ISSUED_STATUS_KEY, const.PO_DRAFT_STATUS_KEY ]: form.status.query = [ EnumValues.get(obj.status.code), ] if obj.status.code == const.PO_DRAFT_STATUS_KEY: form.status.query.append(EnumValues.get( const.PO_ISSUED_STATUS_KEY)) # Set product query option for old lines(forbid to change product for # existing line) line_entries = form.lines.entries products = Product.supplier_filter(supplier_id).all() for sub_line in line_entries: sub_line.form.product.query = products return form
def test_create(self): from psi.app.models import EnumValues type_id = EnumValues.get(const.DIRECT_SELLING_STORE_ORG_TYPE_KEY).id with self.test_client: fixture.login_as_admin(self.test_client) org_name = object_faker.faker.name() org_desc = object_faker.faker.text(max_nb_chars=20) create_url = self.create_endpoint(view='organization') self.assertPageRendered(endpoint=create_url, method=self.test_client.get, expect_contents=['betterlife', '直营店']) self.assertPageRendered(endpoint=create_url, method=self.test_client.post, expect_contents=[org_name, org_desc], data={"type": type_id, "name": org_name, "description": org_desc, "parent": 1}) self.assertDeleteSuccessful(endpoint=url_for('organization.delete_view', id=2, url=url_for('organization.index_view')), deleted_data=[org_name, org_desc]) from psi.app.models import Organization user, pwd = object_faker.user(role_names=['organization_create', 'organization_view', 'organization_delete', 'organization_edit'], organization=Organization.query.get(1)) db_util.save_objects_commit(user) fixture.login_user(self.test_client, user.email, pwd) from psi.app.models import EnumValues org_type = EnumValues.get(const.DIRECT_SELLING_STORE_ORG_TYPE_KEY) self.assertCreateFail(endpoint=create_url, create_data=[org_name, org_desc], data={"type": org_type.id, "name": org_name, "description": org_desc, "parent": 1})
def edit_form(self, obj=None): form = super(DirectPurchaseOrderAdmin, self).edit_form(obj) supplier_id = obj.transient_supplier.id # Set query_factory for newly added line form.lines.form.product.kwargs['query_factory'] = partial( Product.supplier_filter, supplier_id) if not security_util.user_has_role('purchase_price_view'): form_util.del_form_field(self, form, 'goods_amount') form_util.del_form_field(self, form, 'total_amount') form_util.del_inline_form_field(form.lines.form, form.lines.entries, 'unit_price') form_util.del_inline_form_field(form.lines.form, form.lines.entries, 'total_amount') # Set option list of status available if obj.status.code in [const.PO_RECEIVED_STATUS_KEY, const.PO_PART_RECEIVED_STATUS_KEY, const.PO_PART_RECEIVED_STATUS_KEY, const.PO_ISSUED_STATUS_KEY, const.PO_DRAFT_STATUS_KEY]: form.status.query = [EnumValues.get(obj.status.code), ] if obj.status.code == const.PO_DRAFT_STATUS_KEY: form.status.query.append( EnumValues.get(const.PO_ISSUED_STATUS_KEY)) # Set product query option for old lines(forbid to change product for # existing line) line_entries = form.lines.entries products = Product.supplier_filter(supplier_id).all() for sub_line in line_entries: sub_line.form.product.query = products return form
def test_logic(): fixture.login_as_admin(self.test_client) user, password = object_faker.user(role_names=[ 'franchise_sales_order_create', 'franchise_sales_order_view', 'franchise_sales_order_edit', 'product_view' ]) franchise_so_type = EnumValues.get(FRANCHISE_SO_TYPE_KEY) sales_order = object_faker.sales_order(creator=user, number_of_line=1, type=franchise_so_type) db_util.save_objects_commit(sales_order, user) so_id = sales_order.id shipped_status = EnumValues.get(SO_SHIPPED_STATUS_KEY) fixture.login_user(self.test_client, user.email, password) rv = self.test_client.put('/api/sales_order/' + str(so_id), follow_redirects=True, data=dict(status_id=shipped_status.id)) self.assertIn('message', rv.data) self.assertIn('Status update successfully', rv.data) self.assertEqual(rv.status_code, 200) so_from_db = Info.get_db().session.query(SalesOrder).get(so_id) self.assertIsNotNone(so_from_db) self.assertEquals(SO_SHIPPED_STATUS_KEY, so_from_db.status.code)
def create_or_update_incoming(sales_order): incoming = sales_order.incoming default_so_incoming_status = EnumValues.get(const.DEFUALT_SALES_ORDER_INCOMING_STATUS_KEY) default_so_incoming_type = EnumValues.get(const.DEFUALT_SALES_ORDER_INCOMING_TYPE_KEY) incoming = SalesOrderService.create_associated_obj(incoming, sales_order, default_obj=Incoming(), value=sales_order.actual_amount, status_id=default_so_incoming_status.id, type_id=default_so_incoming_type.id) return incoming
def test_logic(): po1, po2 = of.purchase_order(), of.purchase_order() from psi.app.models import EnumValues po1.status = EnumValues.get(const.PO_DRAFT_STATUS_KEY) po2.status = EnumValues.get(const.PO_ISSUED_STATUS_KEY) db_util.save_objects_commit(po1, po2) po3 = PurchaseOrder.status_filter((const.PO_DRAFT_STATUS_KEY,)).all()[0] self.assertIsNotNone(po3) self.assertEqual(po1, po3) po4 = PurchaseOrder.status_filter((const.PO_ISSUED_STATUS_KEY,)).all()[0] self.assertIsNotNone(po4) self.assertEqual(po2, po4)
def create_or_update_expense(sales_order): expense = sales_order.expense default_so_expense_status_id = EnumValues.get(const.DEFUALT_SALES_ORDER_EXPENSE_STATUS_KEY).id default_so_expense_type_id = EnumValues.get(const.DEFUALT_SALES_ORDER_EXPENSE_TYPE_KEY).id if (sales_order.logistic_amount is not None) and (sales_order.logistic_amount > 0): from psi.app.models import Expense default_obj = Expense(sales_order.logistic_amount, sales_order.order_date, default_so_expense_status_id, default_so_expense_type_id) expense = SalesOrderService.create_associated_obj(expense, sales_order, default_obj=default_obj, value=sales_order.logistic_amount, status_id=default_so_expense_status_id, type_id=default_so_expense_type_id) return expense
def test_logic(): type = EnumValues.get(DIRECT_PO_TYPE_KEY) status = EnumValues.get(PO_ISSUED_STATUS_KEY) draft_status = EnumValues.get(RECEIVING_DRAFT_STATUS_KEY) date = object_faker.faker.date_time_this_year() po = object_faker.purchase_order(number_of_line=2, type=type, status=status) db_util.save_objects_commit(po) remark = object_faker.faker.text(max_nb_chars=50) # Crete new receiving self.assertPageRendered( method=self.test_client.post, data=dict(purchase_order=po.id, status=draft_status.id, create_lines='y', date=date, remark=remark), endpoint=self.create_endpoint(view='receiving'), ) # Change status to complete new_remark = object_faker.faker.text(max_nb_chars=50) new_receive_date = object_faker.faker.date_time_this_year() complete_status = EnumValues.get(RECEIVING_COMPLETE_STATUS_KEY) self.assertPageRendered( method=self.test_client.post, endpoint=self.edit_endpoint(view='receiving'), data=dict(date=new_receive_date, status=complete_status.id, remark=new_remark), ) # Should not delete existing receiving with complete status endpoint = url_for('receiving.delete_view', id='1') data = dict(url=url_for('receiving.index_view'), id='1') rv = self.assertPageRendered(method=self.test_client.post, endpoint=endpoint, data=data) self.assertIn(complete_status.display, rv.data) self.assertIn(new_receive_date.strftime("%Y-%m-%d"), rv.data) self.assertIn(new_remark, rv.data) self.assertIn(po.supplier.name, rv.data) self.assertIn(po.order_date.strftime("%Y-%m-%d"), rv.data) self.assertIn(po.remark, rv.data) self.assertIn( 'Receiving document can not be update nor delete on complete status', rv.data)
def test_logic(): po1, po2 = of.purchase_order(), of.purchase_order() from psi.app.models import EnumValues po1.status = EnumValues.get(const.PO_DRAFT_STATUS_KEY) po2.status = EnumValues.get(const.PO_ISSUED_STATUS_KEY) db_util.save_objects_commit(po1, po2) po3 = PurchaseOrder.status_filter( (const.PO_DRAFT_STATUS_KEY, )).all()[0] self.assertIsNotNone(po3) self.assertEqual(po1, po3) po4 = PurchaseOrder.status_filter( (const.PO_ISSUED_STATUS_KEY, )).all()[0] self.assertIsNotNone(po4) self.assertEqual(po2, po4)
def test_create(self): from psi.app.models import EnumValues type_id = EnumValues.get(const.DIRECT_SELLING_STORE_ORG_TYPE_KEY).id with self.test_client: fixture.login_as_admin(self.test_client) org_name = object_faker.faker.name() org_desc = object_faker.faker.text(max_nb_chars=20) create_url = self.create_endpoint(view='organization') self.assertPageRendered( endpoint=create_url, method=self.test_client.get, expect_contents=['betterlife', '直营店']) self.assertPageRendered( endpoint=create_url, method=self.test_client.post, expect_contents=[org_name, org_desc], data={ "type": type_id, "name": org_name, "description": org_desc, "parent": 1 }) self.assertDeleteSuccessful( endpoint=url_for( 'organization.delete_view', id=2, url=url_for('organization.index_view')), deleted_data=[org_name, org_desc]) from psi.app.models import Organization user, pwd = object_faker.user( role_names=[ 'organization_create', 'organization_view', 'organization_delete', 'organization_edit' ], organization=Organization.query.get(1)) db_util.save_objects_commit(user) fixture.login_user(self.test_client, user.email, pwd) from psi.app.models import EnumValues org_type = EnumValues.get(const.DIRECT_SELLING_STORE_ORG_TYPE_KEY) self.assertCreateFail( endpoint=create_url, create_data=[org_name, org_desc], data={ "type": org_type.id, "name": org_name, "description": org_desc, "parent": 1 })
def test_delete_root_not_allowed(self): from psi.app.models import EnumValues type_id = EnumValues.get(const.DIRECT_SELLING_STORE_ORG_TYPE_KEY).id with self.test_client: fixture.login_as_admin(self.test_client) name = object_faker.faker.name() desc = object_faker.faker.text(max_nb_chars=20) self.assertPageRendered( endpoint=url_for( 'organization.edit_view', id=1, url=url_for('organization.index_view')), method=self.test_client.post, expect_contents=[name, desc], data={ "type": type_id, "name": name, "description": desc, "parent": u'__None' }) self.assertPageRendered( endpoint=url_for( 'organization.delete_view', url=url_for('organization.index_view'), id=1), method=self.test_client.post, expect_contents=[name, desc, "1"], data={ "type": type_id, "name": name, "description": desc, "parent": u'__None' })
def test_delete_root_not_allowed(self): from psi.app.models import EnumValues type_id = EnumValues.get(const.DIRECT_SELLING_STORE_ORG_TYPE_KEY).id with self.test_client: fixture.login_as_admin(self.test_client) name = object_faker.faker.name() desc = object_faker.faker.text(max_nb_chars=20) self.assertPageRendered(endpoint=url_for( 'organization.edit_view', id=1, url=url_for('organization.index_view')), method=self.test_client.post, expect_contents=[name, desc], data={ "type": type_id, "name": name, "description": desc, "parent": u'__None' }) self.assertPageRendered(endpoint=url_for( 'organization.delete_view', url=url_for('organization.index_view'), id=1), method=self.test_client.post, expect_contents=[name, desc, "1"], data={ "type": type_id, "name": name, "description": desc, "parent": u'__None' })
def test_delete_normal_allowed(self): from psi.app.models import EnumValues type_id = EnumValues.get(const.DIRECT_SELLING_STORE_ORG_TYPE_KEY).id with self.test_client: fixture.login_as_admin(self.test_client) name, desc = self.create_organization(type_id=type_id, parent_id=1) self.assertDeleteSuccessful(endpoint=url_for('organization.delete_view', id=2, url=url_for('organization.index_view')), deleted_data=[name, desc])
def create_expenses(po): """ Create expense from purchase order Create one record for the goods amount, one record for logistic amount :return: The logistic expense and goods expense """ from psi.app.models import Expense expenses = po.expenses logistic_exp = None default_logistic_exp_type = EnumValues.get( const.DEFAULT_LOGISTIC_EXPENSE_TYPE_KEY) default_goods_exp_type = EnumValues.get( const.DEFAULT_GOODS_EXPENSE_TYPE_KEY) default_logistic_exp_status = EnumValues.get( const.DEFAULT_LOGISTIC_EXPENSE_STATUS_KEY) default_goods_exp_status = EnumValues.get( const.DEFAULT_GOODS_EXPENSE_STATUS_KEY) goods_exp = None if expenses is None: expenses = dict() for expense in expenses: if (expense.category_id == default_logistic_exp_type.id) and ( po.logistic_amount != 0): logistic_exp = expense logistic_exp.amount = po.logistic_amount elif (expense.category_id == default_goods_exp_type.id) and (po.goods_amount != 0): goods_exp = expense goods_exp.amount = po.goods_amount if (logistic_exp is None) and (po.logistic_amount is not None and po.logistic_amount != 0): logistic_exp = Expense(po.logistic_amount, po.order_date, default_logistic_exp_status.id, default_logistic_exp_type.id) if (goods_exp is None) and (po.goods_amount is not None and po.goods_amount != 0): goods_exp = Expense(po.goods_amount, po.order_date, default_goods_exp_status.id, default_goods_exp_type.id) if logistic_exp is not None: logistic_exp.purchase_order = po logistic_exp.organization = po.organization if goods_exp is not None: goods_exp.purchase_order = po goods_exp.organization = po.organization return logistic_exp, goods_exp
def test_enough_inventory(self): from psi.app.services.purchase_order import PurchaseOrderService with self.test_client: from tests.fixture import login_as_admin from psi.app.services import SalesOrderService from psi.app.models import EnumValues login_as_admin(self.test_client) po = of.purchase_order(number_of_line=2, type=EnumValues.get( const.DIRECT_PO_TYPE_KEY)) products = [l.product for l in po.lines] receiving = PurchaseOrderService.create_receiving_if_not_exist(po) receiving.status = EnumValues.get( const.RECEIVING_COMPLETE_STATUS_KEY) in_trans_line = receiving.operate_inv_trans_by_recv_status() po = receiving.update_purchase_order_status() from psi.app.utils import db_util db_util.save_objects_commit(po, receiving, in_trans_line) so = of.sales_order(products=products, number_of_line=2) shipping = SalesOrderService.create_or_update_shipping(so) db_util.save_objects_commit(so, shipping) out_inv_trans = shipping.inventory_transaction self.assertIsNotNone(out_inv_trans) self.assertEquals(2, len(out_inv_trans.lines)) for l in shipping.lines: self.assertEquals(1, len(l.inventory_links)) link = l.inventory_links[0] self.assertIsNotNone(link) so_line = None for l in so.lines: if l.product.id == link.product.id: self.assertEquals(link.out_price, l.unit_price) self.assertEquals(link.out_quantity, l.quantity) so_line = l for recv_l in receiving.lines: if recv_l.product.id == link.product.id: self.assertEquals(link.in_price, recv_l.price) in_trans_line = recv_l.inventory_transaction_line remain_qty = recv_l.purchase_order_line.quantity - so_line.quantity if remain_qty < 0: self.assertEquals(0, in_trans_line.saleable_quantity) else: self.assertEquals(remain_qty, in_trans_line.saleable_quantity)
def update_related_po_status(sales_order, status_code): purchase_order = SalesOrderService.get_related_po(sales_order) session = Info.get_db().session if purchase_order is not None: status = EnumValues.get(status_code) purchase_order.status = status session.add(purchase_order) return purchase_order
def create_form(self, obj=None): from psi.app.models import Supplier form = super(DirectPurchaseOrderAdmin, self).create_form(obj) form.status.query = [ EnumValues.get(const.PO_DRAFT_STATUS_KEY), ] form_util.filter_by_organization(form.supplier, Supplier) return form
def create_form(self, obj=None): from psi.app.models import EnumValues form = super(ReceivingAdmin, self).create_form(obj) form.status.query = [ EnumValues.get(const.RECEIVING_DRAFT_STATUS_KEY), ] form.create_lines.data = True return form
def get_related_po(sales_order): rt = EnumValues.get(const.FRANCHISE_PO_TO_SO_RT_KEY) session = Info.get_db().session related_value, purchase_order = None, None if sales_order.type.code == const.FRANCHISE_SO_TYPE_KEY: related_value = session.query(RelatedValues).filter_by(to_object_id=sales_order.id, relation_type_id=rt.id).first() if related_value is not None: purchase_order = session.query(PurchaseOrder).get(related_value.from_object_id) return purchase_order
def test_logic(): type = EnumValues.get(DIRECT_PO_TYPE_KEY) status = EnumValues.get(PO_ISSUED_STATUS_KEY) receiving_status = EnumValues.get(RECEIVING_DRAFT_STATUS_KEY) date = object_faker.faker.date_time_this_year() po = object_faker.purchase_order(number_of_line=2, type=type, status=status) db_util.save_objects_commit(po) remark = object_faker.faker.text(max_nb_chars=50) list_expect = [receiving_status.display, date.strftime("%Y-%m-%d"), remark, po.supplier.name, po.order_date.strftime("%Y-%m-%d"), po.remark] edit_expect = [receiving_status.display, date.strftime("%Y-%m-%d"), remark,] # Crete new receiving self.assertPageRendered(method=self.test_client.post, data=dict(purchase_order=po.id, status=receiving_status.id, create_lines='y', date=date, remark=remark), endpoint=self.create_endpoint(view='receiving'), expect_contents=list_expect) self.assertPageRendered(expect_contents=edit_expect, endpoint=self.edit_endpoint(view='receiving')) # Edit existing receiving new_remark = object_faker.faker.text(max_nb_chars=50) new_receive_date = object_faker.faker.date_time_this_year() complete_status = EnumValues.get(RECEIVING_COMPLETE_STATUS_KEY) new_expected = [complete_status.display, new_receive_date.strftime("%Y-%m-%d"), new_remark, po.supplier.name, po.order_date.strftime("%Y-%m-%d"), po.remark] self.assertPageRendered(method=self.test_client.post, endpoint=self.edit_endpoint(view='receiving'), data=dict(date=new_receive_date, status=complete_status.id, remark=new_remark), expect_contents=new_expected) # Detail page self.assertPageRendered(method=self.test_client.get, endpoint=self.details_endpoint(view='receiving'), expect_contents=new_expected)
def render(self, context, row_id, row): kwargs = dict(self.url_args) if self.url_args else {} kwargs[self.id_arg] = row_id so_shipped_status = EnumValues.get(const.SO_SHIPPED_STATUS_KEY) if row.status.code == const.SO_CREATED_STATUS_KEY and row.type.code == const.FRANCHISE_SO_TYPE_KEY: return Markup("""<a class='icon' href='javascript:MarkShipRowAction({0}, {1})'> <span id='mark_ship_row_action_{0}' class='fa fa-truck'></span> </a>""".format(row_id, so_shipped_status.id)) else: return ''
def test_to_organization_hide(self): from psi.app.models import EnumValues, PurchaseOrder, Organization from psi.app.service import Info from datetime import datetime t = EnumValues.get(const.FRANCHISE_STORE_ORG_TYPE_KEY) draft_status = EnumValues.get(const.PO_DRAFT_STATUS_KEY) draft_status_id = draft_status.id parent = Info.get_db().session.query(Organization).get(1) organization = object_faker.organization(type=t, parent=parent) user, password = object_faker.user([ 'franchise_purchase_order_create', 'franchise_purchase_order_edit', 'franchise_purchase_order_view', 'franchise_purchase_order_delete' ], organization=organization) db_util.save_objects_commit(user) fixture.login_user(self.test_client, user.email, password) rv = self.test_client.get(url_for('fpo.create_view'), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertNotIn('to_organization', rv.data) remark = u'-备注信息-' order_date = '2016-08-25 23:18:55' rv = self.test_client.post(url_for('fpo.create_view'), follow_redirects=True, data=dict(status=draft_status_id, logistic_amount=20, order_date=order_date, _continue_editing=u'保存并继续编辑', remark=remark)) self.assertEquals(rv.status_code, 200) po = PurchaseOrder.query.filter_by(remark=remark).first() self.assertIsNotNone(po) self.assertEquals(po.remark, remark) self.assertEquals(po.logistic_amount, 20) self.assertEquals(po.status.id, draft_status.id) self.assertEqual(po.order_date, datetime.strptime(order_date, "%Y-%m-%d %H:%M:%S")) self.assertEqual(po.to_organization, parent) self.assertEquals(po.organization, organization)
def on_model_change(self, form, model, is_created): super(SalesOrderAdmin, self).on_model_change(form, model, is_created) if is_created: model.type = EnumValues.get(const.DIRECT_SO_TYPE_KEY) if model.status is None: model.status = EnumValues.get(const.SO_DELIVERED_STATUS_KEY) model.organization = current_user.organization if model.status.code == const.SO_DELIVERED_STATUS_KEY: incoming = SalesOrderService.create_or_update_incoming(model) expense = SalesOrderService.create_or_update_expense(model) shipping = None if model.type.code == const.DIRECT_SO_TYPE_KEY: shipping = SalesOrderService.create_or_update_shipping(model) db = service.Info.get_db() if expense is not None: db.session.add(expense) if incoming is not None: db.session.add(incoming) if shipping is not None: db.session.add(shipping)
def test_delete_with_child_not_allowed(self): from psi.app.models import EnumValues, Organization type_id = EnumValues.get(const.DIRECT_SELLING_STORE_ORG_TYPE_KEY).id with self.test_client: fixture.login_as_admin(self.test_client) name1, desc1 = self.create_organization(type_id=type_id, parent_id=1) self.create_organization(type_id=type_id, parent_id=2) self.assertDeleteFail(endpoint=url_for('organization.delete_view', id=2, url=url_for('organization.index_view')), deleted_data=[name1, desc1]) org = Organization.query.get(2) self.assertIsNotNone(org)
def create_related_value(sales_order, purchase_order): from psi.app.models import RelatedValues rv = RelatedValues() rv.from_object_id = purchase_order.id rv.from_object_type = "PurchaseOrder" rv.to_object_id = sales_order.id rv.to_object_type = "SalesOrder" from psi.app.const import FRANCHISE_PO_TO_SO_RT_KEY related_type = EnumValues.get(FRANCHISE_PO_TO_SO_RT_KEY) rv.relation_type = related_type return rv
def test_enough_inventory(self): from psi.app.services.purchase_order import PurchaseOrderService with self.test_client: from tests.fixture import login_as_admin from psi.app.services import SalesOrderService from psi.app.models import EnumValues login_as_admin(self.test_client) po = of.purchase_order(number_of_line=2, type=EnumValues.get(const.DIRECT_PO_TYPE_KEY)) products = [l.product for l in po.lines] receiving = PurchaseOrderService.create_receiving_if_not_exist(po) receiving.status = EnumValues.get(const.RECEIVING_COMPLETE_STATUS_KEY) in_trans_line = receiving.operate_inv_trans_by_recv_status() po = receiving.update_purchase_order_status() from psi.app.utils import db_util db_util.save_objects_commit(po, receiving, in_trans_line) so = of.sales_order(products=products, number_of_line=2) shipping = SalesOrderService.create_or_update_shipping(so) db_util.save_objects_commit(so, shipping) out_inv_trans = shipping.inventory_transaction self.assertIsNotNone(out_inv_trans) self.assertEquals(2,len(out_inv_trans.lines)) for l in shipping.lines: self.assertEquals(1, len(l.inventory_links)) link = l.inventory_links[0] self.assertIsNotNone(link) so_line = None for l in so.lines: if l.product.id == link.product.id: self.assertEquals(link.out_price, l.unit_price) self.assertEquals(link.out_quantity, l.quantity) so_line = l for recv_l in receiving.lines: if recv_l.product.id == link.product.id: self.assertEquals(link.in_price, recv_l.price) in_trans_line = recv_l.inventory_transaction_line remain_qty = recv_l.purchase_order_line.quantity - so_line.quantity if remain_qty < 0: self.assertEquals(0, in_trans_line.saleable_quantity) else: self.assertEquals(remain_qty, in_trans_line.saleable_quantity)
def test_logic(): type = EnumValues.get(DIRECT_PO_TYPE_KEY) status = EnumValues.get(PO_ISSUED_STATUS_KEY) draft_status = EnumValues.get(RECEIVING_DRAFT_STATUS_KEY) date = object_faker.faker.date_time_this_year() po = object_faker.purchase_order(number_of_line=2, type=type, status=status) db_util.save_objects_commit(po) remark = object_faker.faker.text(max_nb_chars=50) # Crete new receiving self.assertPageRendered(method=self.test_client.post, data=dict(purchase_order=po.id, status=draft_status.id, create_lines='y', date=date, remark=remark), endpoint=self.create_endpoint(view='receiving'),) # Change status to complete new_remark = object_faker.faker.text(max_nb_chars=50) new_receive_date = object_faker.faker.date_time_this_year() complete_status = EnumValues.get(RECEIVING_COMPLETE_STATUS_KEY) self.assertPageRendered(method=self.test_client.post, endpoint=self.edit_endpoint(view='receiving'), data=dict(date=new_receive_date, status=complete_status.id, remark=new_remark),) # Should not delete existing receiving with complete status endpoint = url_for('receiving.delete_view', id='1') data = dict(url=url_for('receiving.index_view'), id='1') rv = self.assertPageRendered(method=self.test_client.post, endpoint=endpoint, data=data) self.assertIn(complete_status.display.encode('utf-8'), rv.data) self.assertIn(new_receive_date.strftime("%Y-%m-%d").encode('utf-8'), rv.data) self.assertIn(new_remark.encode('utf-8'), rv.data) self.assertIn(po.supplier.name.encode('utf-8'), rv.data) self.assertIn(po.order_date.strftime("%Y-%m-%d").encode('utf-8'),rv.data) self.assertIn(po.remark.encode('utf-8'), rv.data) self.assertIn(b'You are not allowed to delete this object', rv.data)
def test_franchise_purchase_order_pages(self): from psi.app.models import EnumValues, Organization org_type = EnumValues.get(const.FRANCHISE_STORE_ORG_TYPE_KEY) organization = object_faker.organization(parent=Organization.query.get(1), type=org_type) user, pwd = object_faker.user( role_names=['franchise_purchase_order_create', 'franchise_purchase_order_edit', 'franchise_purchase_order_delete', 'franchise_purchase_order_view'], organization=organization) db_util.save_objects_commit(user, organization) login_user(self.test_client, user.email, pwd) self.assertPageRendered(url_for('fpo.index_view'))
def on_model_change(self, form, model, is_created): super(BasePurchaseOrderAdmin, self).on_model_change(form, model, is_created) if not security_util.user_has_role('purchase_price_view'): for l in model.lines: l.unit_price = l.product.purchase_price DeleteValidator.validate_status_for_change( model, const.PO_RECEIVED_STATUS_KEY, gettext('Purchase order can not be update nor delete on received status') ) if is_created: model.type = EnumValues.get(self.type_code) PurchaseOrderService.create_expense_receiving(model)
def test_login(): from psi.app.models import EnumValues f_type = EnumValues.get(const.FRANCHISE_PO_TYPE_KEY) po = object_faker.purchase_order(number_of_line=random.randint( 1, 10), type=f_type) db_util.save_objects_commit(po) from psi.app.views import FranchisePurchaseOrderAdmin sales_order, incoming, expense = FranchisePurchaseOrderAdmin.create_so_from_fpo( po) self.assertEquals(len(po.lines), len(sales_order.lines)) self.assertEqual(sales_order.order_date, po.order_date) self.assertEquals(sales_order.type, EnumValues.get(const.FRANCHISE_SO_TYPE_KEY)) self.assertEquals(sales_order.status, EnumValues.get(const.SO_CREATED_STATUS_KEY)) self.assertEquals(sales_order.organization, po.to_organization) # There's no expense associated with the PO when creating PO for the franchise organization. # That's done on after_model_change in BasePurchaseOrderAdmin class self.assertEquals(sales_order.actual_amount, incoming.amount) self.assertIsNone(expense)
def create_so_from_fpo(purchase_order): so_type = EnumValues.get(const.FRANCHISE_SO_TYPE_KEY) sales_order = SalesOrder() sales_order.id = db_util.get_next_id(SalesOrder) sales_order.order_date = purchase_order.order_date sales_order.type = so_type sales_order.remark = "PO ID: [{0}]".format(purchase_order.id) sales_order.organization = purchase_order.to_organization sales_order.status = EnumValues.get(const.SO_CREATED_STATUS_KEY) lines = [] for line in purchase_order.lines: sol = SalesOrderLine() sol.unit_price = line.unit_price sol.quantity = line.quantity sol.sales_order = sales_order sol.product = line.product sol.remark = "PO Line ID:[{0}]".format(line.id) lines.append(sol) from psi.app.services import SalesOrderService incoming = SalesOrderService.create_or_update_incoming(sales_order) expense = SalesOrderService.create_or_update_expense(sales_order) return sales_order, incoming, expense
def test_logic(): from psi.app.models import Receiving, EnumValues from psi.app.views import ReceivingAdmin from psi.app.service import Info receiving = Receiving() complete_status = EnumValues.get(RECEIVING_COMPLETE_STATUS_KEY) receiving.status = complete_status db_session = Info.get_db().session receiving_admin = ReceivingAdmin(Receiving, db_session, name=lazy_gettext("Receiving"), category=lazy_gettext('Purchase'), menu_icon_type=ICON_TYPE_GLYPH, menu_icon_value='glyphicon-import') self.assertRaises(ValidationError, receiving_admin.on_model_delete, receiving)
def create_sales_order(self, status_key): from psi.app.models import EnumValues from psi.app.services.purchase_order import PurchaseOrderService user, password = of.user( role_names=['direct_sales_order_create', 'direct_sales_order_view', 'direct_sales_order_edit', 'direct_sales_order_delete'] ) db_util.save_objects_commit(user) fixture.login_as_admin(self.test_client) fixture.login_user(self.test_client, user.email, password) direct_po = EnumValues.get(const.DIRECT_PO_TYPE_KEY) po = of.purchase_order(number_of_line=2, type=direct_po, creator=user) po.status = EnumValues.get(const.PO_ISSUED_STATUS_KEY) fixture.login_as_admin(self.test_client) l_e, g_e, recv = PurchaseOrderService.create_expense_receiving(po) customer = of.customer(creator=user) db_util.save_objects_commit(po, l_e, g_e, recv, customer) fixture.logout_user(self.test_client) fixture.login_user(self.test_client, user.email, password) order_status = EnumValues.get(status_key) order_date = of.faker.date_time_this_year() logistic_amount = random.randint(0, 100) remark = of.faker.text(max_nb_chars=50) data = dict(customer=customer.id, status=order_status.id, order_date=order_date, logistic_amount=logistic_amount, remark=remark) total, data = self.prepare_so_lines_data_from_po(po, data) expect = [customer.name, order_status.display, order_date.strftime("%Y-%m-%d"), remark, str(total)] self.assertPageRendered(method=self.test_client.post, data=data, endpoint=url_for('salesorder.create_view', url=url_for( 'salesorder.index_view')), expect_contents=expect) return data, expect
def adjust_product_quantity(product, date, quantity, price, type_code): from psi.app.models import InventoryTransactionLine, InventoryTransaction, EnumValues it = InventoryTransaction() it.date = date it.type = EnumValues.get(type_code) itl = InventoryTransactionLine() itl.quantity = quantity itl.product_id = product.id itl.inventory_transaction = it itl.price = price if product.inventory_transaction_lines is None: product.inventory_transaction_lines = [itl] else: product.inventory_transaction_lines.append(itl)
def on_model_change(self, form, model, is_created): super(BasePurchaseOrderAdmin, self).on_model_change( form, model, is_created) if not security_util.user_has_role('purchase_price_view'): for l in model.lines: l.unit_price = l.product.purchase_price DeleteValidator.validate_status_for_change( model, const.PO_RECEIVED_STATUS_KEY, gettext( 'Purchase order can not be update nor delete on received status' )) if is_created: model.type = EnumValues.get(self.type_code) PurchaseOrderService.create_expense_receiving(model)
def create_or_update_shipping(sales_order): status = EnumValues.get(const.SHIPPING_COMPLETE_STATUS_KEY) shipping = sales_order.so_shipping if shipping is None: shipping = Shipping() shipping.date = sales_order.order_date shipping.sales_order = sales_order shipping.status = status if sales_order.type.code == const.DIRECT_SO_TYPE_KEY: shipping.type = EnumValues.get(const.DIRECT_SHIPPING_TYPE_KEY) elif sales_order.type.code == const.FRANCHISE_SO_TYPE_KEY: shipping.type = EnumValues.get(const.FRANCHISE_SHIPPING_TYPE_KEY) shipping.organization = sales_order.organization for line in sales_order.lines: new_sl = None for old_sl in shipping.lines: if old_sl.sales_order_line_id == line.id: new_sl = old_sl break new_sl = SalesOrderService.copy_sales_order_line_to_shipping_line(line, new_sl) new_sl.shipping = shipping shipping.create_or_update_inventory_transaction() return shipping
def test_franchise_purchase_order_pages(self): from psi.app.models import EnumValues, Organization org_type = EnumValues.get(const.FRANCHISE_STORE_ORG_TYPE_KEY) organization = object_faker.organization( parent=Organization.query.get(1), type=org_type) user, pwd = object_faker.user(role_names=[ 'franchise_purchase_order_create', 'franchise_purchase_order_edit', 'franchise_purchase_order_delete', 'franchise_purchase_order_view' ], organization=organization) db_util.save_objects_commit(user, organization) login_user(self.test_client, user.email, pwd) self.assertPageRendered(url_for('fpo.index_view'))
def create_sales_order(self, status_key): from psi.app.models import EnumValues from psi.app.services.purchase_order import PurchaseOrderService user, password = of.user( role_names=['direct_sales_order_create', 'direct_sales_order_view', 'direct_sales_order_edit', 'direct_sales_order_delete'] ) db_util.save_objects_commit(user) fixture.login_as_admin(self.test_client) fixture.login_user(self.test_client, user.email, password) direct_po = EnumValues.get(const.DIRECT_PO_TYPE_KEY) po = of.purchase_order(number_of_line=2, type=direct_po, creator=user) po.status = EnumValues.get(const.PO_ISSUED_STATUS_KEY) fixture.login_as_admin(self.test_client) l_e, g_e, recv = PurchaseOrderService.create_expense_receiving(po) customer = of.customer(creator=user) db_util.save_objects_commit(po, l_e, g_e, recv, customer) fixture.logout_user(self.test_client) fixture.login_user(self.test_client, user.email, password) order_status = EnumValues.get(status_key) order_date = of.faker.date_time_this_year() logistic_amount = random.randint(0, 100) remark = of.faker.text(max_nb_chars=50) data = dict(customer=customer.id, status=order_status.id, order_date=order_date, logistic_amount=logistic_amount, remark=remark) total, data = self.prepare_so_lines_data_from_po(po, data) expect = [customer.name, order_status.display, order_date.strftime("%Y-%m-%d"), remark, str(total)] self.assertPageRendered(method=self.test_client.post, data=data, endpoint=self.create_endpoint(view='salesorder'), expect_contents=expect) return data, expect
def test_status_options(self): from psi.app.models import PurchaseOrder, EnumValues po_statuses = PurchaseOrder.status_option_filter().all() self.assertEquals(len(po_statuses), 6) self.assertIn(EnumValues.get(const.PO_ISSUED_STATUS_KEY), po_statuses) self.assertIn(EnumValues.get(const.PO_DRAFT_STATUS_KEY), po_statuses) self.assertIn(EnumValues.get(const.PO_REJECTED_STATUS_KEY), po_statuses) self.assertIn(EnumValues.get(const.PO_PART_RECEIVED_STATUS_KEY), po_statuses) self.assertIn(EnumValues.get(const.PO_RECEIVED_STATUS_KEY), po_statuses) self.assertIn(EnumValues.get(const.PO_SHIPPED_STATUS_KEY), po_statuses)
def test_delete_with_child_not_allowed(self): from psi.app.models import EnumValues, Organization type_id = EnumValues.get(const.DIRECT_SELLING_STORE_ORG_TYPE_KEY).id with self.test_client: fixture.login_as_admin(self.test_client) name1, desc1 = self.create_organization( type_id=type_id, parent_id=1) self.create_organization(type_id=type_id, parent_id=2) self.assertDeleteFail( endpoint=url_for( 'organization.delete_view', id=2, url=url_for('organization.index_view')), deleted_data=[name1, desc1]) org = Organization.query.get(2) self.assertIsNotNone(org)
def test_logic(): fixture.login_as_admin(self.test_client) user, password = object_faker.user(role_names=[ 'franchise_sales_order_create', 'franchise_sales_order_view', 'product_view' ]) sales_order = object_faker.sales_order(creator=user, number_of_line=1) db_util.save_objects_commit(sales_order, user) so_id = sales_order.id delivered_status = EnumValues.get(SO_DELIVERED_STATUS_KEY) fixture.login_user(self.test_client, user.email, password) rv = self.test_client.put('/api/sales_order/' + str(so_id), follow_redirects=True, data=dict(status_id=delivered_status.id)) self.assertEqual(rv.status_code, 403)
def edit_form(self, obj=None): from psi.app.models import PurchaseOrderLine, EnumValues form = super(ReceivingAdmin, self).edit_form(obj) po_id = obj.transient_po.id # Set query_factory for newly added line form.lines.form.purchase_order_line.kwargs['query_factory'] = partial(PurchaseOrderLine.header_filter, po_id) if obj is not None and obj.status is not None and obj.status.code == const.RECEIVING_COMPLETE_STATUS_KEY: form.status.query = [EnumValues.get(const.RECEIVING_COMPLETE_STATUS_KEY), ] # Set query option for old lines line_entries = form.lines.entries po_lines = PurchaseOrderLine.header_filter(po_id).all() if not security_util.user_has_role('purchase_price_view'): form_util.del_form_field(self, form, 'total_amount') form_util.del_inline_form_field(form.lines.form, form.lines.entries, 'transient_price') form_util.del_inline_form_field(form.lines.form, form.lines.entries, 'total_amount') for sub_line in line_entries: sub_line.form.purchase_order_line.query = po_lines return form
def test_logic(): fixture.login_as_admin(self.test_client) user, password = object_faker.user(role_names=[ 'franchise_sales_order_create', 'franchise_sales_order_view', 'franchise_sales_order_edit', 'product_view' ]) sales_order = object_faker.sales_order(creator=user, number_of_line=1) shipped_status = EnumValues.get(SO_SHIPPED_STATUS_KEY) sales_order.status = shipped_status db_util.save_objects_commit(sales_order, user) so_id = sales_order.id fixture.login_user(self.test_client, user.email, password) rv = self.test_client.put('/api/sales_order/' + str(so_id), follow_redirects=True, data=dict(status_id=shipped_status.id)) self.assertEqual(rv.status_code, 201) self.assertIn(b'message', rv.data) self.assertIn(b'Status update not allowed', rv.data)
def create_form(self, obj=None): from psi.app.models import Supplier form = super(DirectPurchaseOrderAdmin, self).create_form(obj) form.status.query = [EnumValues.get(const.PO_DRAFT_STATUS_KEY), ] form_util.filter_by_organization(form.supplier, Supplier) return form
def get_count_query(self): po_type = EnumValues.get(self.type_code) return super(BasePurchaseOrderAdmin, self).get_count_query().filter(self.model.type == po_type)