Skip to content

Commit

Permalink
Fix test failures and add working code for Supplier reports.
Browse files Browse the repository at this point in the history
  • Loading branch information
xqliu committed May 31, 2017
1 parent c1703d4 commit 7375424
Show file tree
Hide file tree
Showing 18 changed files with 636 additions and 112 deletions.
2 changes: 2 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def clean_transaction_data():
"""
Clean all the transaction data, and keep all master data
"""
# TODO.xqliu Disable clean of database for production
database.engine.execute("""
DELETE FROM related_values;
DELETE FROM inventory_in_out_link;
Expand All @@ -93,6 +94,7 @@ def clean_database():
Clean the database and drop all the tables
This only tested for postgresql at this moment
"""
# TODO.xqliu Disable clean of database for production
database.engine.execute("""
DROP VIEW sales_order_detail RESTRICT;
ALTER TABLE related_values DROP CONSTRAINT related_values_relation_type_id_fkey;
Expand Down
2 changes: 1 addition & 1 deletion psi/app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class BaseConfig(object):

class DevConfig(BaseConfig):
DEBUG = True
SQLALCHEMY_ECHO = False
SQLALCHEMY_ECHO = False
IMAGE_STORE_SERVICE = LocalImageStore
SEND_FILE_MAX_AGE_DEFAULT = 1

Expand Down
3 changes: 2 additions & 1 deletion psi/app/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
from role import Role, roles_users
from organization import Organization
from inventory_in_out_link import InventoryInOutLink
from aspects import update_menemonic
from aspects import update_menemonic
from product_inventory import ProductInventory
2 changes: 1 addition & 1 deletion psi/app/models/sales_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class SalesOrderLine(db.Model):
external_id = Column(String(), nullable=True)

product_id = Column(Integer, ForeignKey('product.id'), nullable=False)
product = relationship('Product')
product = relationship('Product', backref=backref('sales_order_lines'))
remark = Column(Text)

@hybrid_property
Expand Down
408 changes: 355 additions & 53 deletions psi/app/models/supplier_sales.py

Large diffs are not rendered by default.

17 changes: 0 additions & 17 deletions psi/app/reports/sqls.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,3 @@
ORDER BY yyyy ASC, period ASC
LIMIT {1};
"""

SUPPLIER_AMOUNT_SQL = u"""
select sum(sol.unit_price*sol.quantity)
from sales_order_line sol,
product prd
where sol.product_id = prd.id AND
prd.supplier_id = {supplier_id};
"""

SUPPLIER_PROFIT_SQL = u"""
select sum((sol.unit_price - prd.purchase_price)*sol.quantity)
from sales_order_line sol,
product prd
where sol.product_id = prd.id AND
prd.supplier_id = {supplier_id};
"""

Binary file modified psi/app/translations/zh_Hans_CN/LC_MESSAGES/messages.mo
Binary file not shown.
5 changes: 4 additions & 1 deletion psi/app/translations/zh_Hans_CN/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2015-06-26 07:25+0800\n"
"PO-Revision-Date: 2017-05-26 23:48+0800\n"
"PO-Revision-Date: 2017-05-28 02:29+0800\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -669,3 +669,6 @@ msgstr "平均日销售额"

msgid "Supplier Sales Report"
msgstr "供应商销售统计"

msgid "Last Month"
msgstr "上个月"
6 changes: 2 additions & 4 deletions psi/app/utils/ui_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ def is_list_field(model, field):
:return: True if attribute with the name is a list field, False otherwise.
"""
import sqlalchemy
field_type = type(getattr(model, field))
same_type = (field_type == sqlalchemy.orm.collections.InstrumentedList)
return same_type

return (type(getattr(model, field)) == sqlalchemy.orm.collections.InstrumentedList)\
if hasattr(model, field) else False

def has_detail_field(form_or_view):
"""
Expand Down
4 changes: 2 additions & 2 deletions psi/app/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from product import ProductAdmin
from product_category import ProductCategoryAdmin
from psi.app.models.product_inventory import ProductInventory
from psi.app.models.supplier_sales import SupplierSales
from psi.app.models.supplier_sales import OverallSupplierSales
from psi.app.views.supplier_sales_report import SupplierSalesReportAdmin
from sales_order import SalesOrderAdmin
from user import UserAdmin
Expand Down Expand Up @@ -173,7 +173,7 @@ def init_admin_views(app, db):
url="report/sales_profit"),
)
admin_views.add_view(SupplierSalesReportAdmin(
SupplierSales,
OverallSupplierSales,
db_session,
name=lazy_gettext("Supplier Sales Report"),
category=lazy_gettext('Report'),
Expand Down
2 changes: 1 addition & 1 deletion psi/app/views/product_inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def role_identify(self): return "product_inventory"
'average_purchase_price', 'average_retail_price', 'average_unit_profit', 'weekly_sold_qty',
'weekly_average_profit', 'inventory_advice')

column_searchable_list = ('name', 'supplier.name')
column_searchable_list = ('name', 'supplier.name', 'mnemonic', 'supplier.mnemonic')

column_filters = (FloatSmallerFilter(Product.available_quantity, lazy_gettext('Available Quantity')),
FloatGreaterFilter(Product.available_quantity, lazy_gettext('Available Quantity')),
Expand Down
25 changes: 25 additions & 0 deletions psi/app/views/report_view_with_access.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from psi.app.views import ModelViewWithAccess


class ReportViewWithAccess(ModelViewWithAccess):
can_edit = False
can_delete = False
can_create = False
can_view_details = False
page_size = 100
report_type = None
sub_reports = []
report_models = dict()

list_template = 'admin/report/list.html'

def get_list(self, page, sort_column, sort_desc, search, filters,
execute=True, page_size=None):
from flask import request
self.report_type = request.args.get('type') \
if request.args.get('type') is not None else self.report_type
model_type = self.report_models.get(self.report_type)
self.model = model_type if model_type is not None else self.model
return super(ReportViewWithAccess, self).get_list(page, sort_column, sort_desc,
search, filters,
execute=True, page_size=None)
2 changes: 1 addition & 1 deletion psi/app/views/sales_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from psi.app.views.formatter import product_field, quantity_field, \
retail_price_field, \
original_amount_field, remark_field, discount_amount_field, \
actual_amount_field, line_formatter
actual_amount_field
from psi.app import service, const
from psi.app.models import EnumValues, Customer, Product
from psi.app.services.sales_order import SalesOrderService
Expand Down
51 changes: 33 additions & 18 deletions psi/app/views/supplier_sales_report.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from psi.app.views import ModelViewWithAccess
from psi.app.views.formatter import supplier_formatter, product_formatter
from flask_babelex import lazy_gettext

from psi.app.models.supplier_sales import OverallSupplierSales, \
LastMonthSupplierSales, YesterdaySupplierSales, LastWeekSupplierSales
from psi.app.views.report_view_with_access import ReportViewWithAccess

class SupplierSalesReportAdmin(ModelViewWithAccess):
can_edit = False
can_delete = False
can_create = False
can_view_details = False

# TODO.1 Sorting is not working
# TODO.2 Need to display translated report in UI
class SupplierSalesReportAdmin(ReportViewWithAccess):

column_default_sort = ('sales_profit', True)

Expand All @@ -18,17 +18,32 @@ def role_identify(self):
column_searchable_list = ('name', 'mnemonic')

column_list = ('name', 'sales_amount', 'sales_profit',
'daily_profit', 'daily_amount',)
'daily_profit', 'daily_amount')

@property
def sub_reports(self):
reps = ['yesterday', 'last_week', 'last_month', 'last_quarter',
'last_year', 'overall']
return [(x, lazy_gettext(x.replace('_',' ').title())) for x in reps]

report_models = dict(
overall=OverallSupplierSales,
last_month=LastMonthSupplierSales,
yesterday=YesterdaySupplierSales,
last_week=LastWeekSupplierSales,
)

report_type = 'yesterday'

column_formatters = {
'supplier': supplier_formatter,
'product': product_formatter,
}

column_filters = {
# 'sales_profit',
# 'sales_date',
}
column_filters = [
'sales_profit',
'sales_amount',
'daily_profit',
'daily_amount',
]

column_labels = {
'name': lazy_gettext('Name'),
Expand All @@ -39,12 +54,12 @@ def role_identify(self):
}

def get_query(self):
return super(SupplierSalesReportAdmin, self)\
.get_query().filter(self.model.sales_amount > 0)
return super(SupplierSalesReportAdmin, self).get_query()\
.filter(self.model.sales_amount > 0)

def get_count_query(self):
return super(SupplierSalesReportAdmin, self)\
.get_count_query().filter(self.model.sales_amount > 0)
return super(SupplierSalesReportAdmin, self).get_count_query()\
.filter(self.model.sales_amount > 0)

column_sortable_list = ('sales_profit', 'sales_amount', 'daily_profit',
'daily_amount',)
21 changes: 11 additions & 10 deletions psi/migrations/versions/39_052340beb7b5_.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,31 @@
from sqlalchemy import text



def upgrade():
from psi.app.models import Supplier, Product, Customer
from psi.app.service import Info
# Follow line is needed to persist all existing migration to DB and avoid
# tests to complain supplier, product and customer tables does not exist
op.get_bind().execute(text("COMMIT;"))
db = Info.get_db()
set_mnemonic_for_all(db, obj_type=Supplier)
set_mnemonic_for_all(db, obj_type=Product)
set_mnemonic_for_all(db, obj_type=Customer)
set_mnemonic_for_all(db, fields=['id', 'name'], obj_type="supplier")
set_mnemonic_for_all(db, fields=['id', 'name'], obj_type="product")
set_mnemonic_for_all(db, fields=['id', 'first_name', 'last_name'], obj_type="customer")
db.session.commit()
# ### end Alembic commands ###


def set_mnemonic_for_all(db, obj_type):
objs = db.session.query(obj_type).all()
def set_mnemonic_for_all(db, fields, obj_type):
join = ",".join(fields) if len(fields) > 0 else fields[0]
objs = op.get_bind().execute(text("select {0} from {1}".format(join, obj_type))).fetchall()
for s in objs:
from psi.app.utils import get_pinyin_first_letters
v = s.get_value_for_mnemonic() if hasattr(s, 'get_value_for_mnemonic') else s.name
v = ''
s_id = s[0]
for i in range(1, len(fields)):
v += s[i]
m = get_pinyin_first_letters(v)
s.mnemonic = m
db.session.add(s)

op.get_bind().execute(text("update {0} set mnemonic = '{1}' where id={2}".format(obj_type, m, s_id)))

def downgrade():
op.get_bind().execute(text("update supplier set mnemonic = '';"))
Expand Down
1 change: 1 addition & 0 deletions psi/migrations/versions/40_e1f806a716b9_.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def upgrade():
nullable=False, existing_server_default=sa.text(u'true'))
op.alter_column('shipping', 'type_id', existing_type=sa.INTEGER(), nullable=False)
op.add_column('supplier', sa.Column('create_date', sa.DateTime(), nullable=True))
op.get_bind().execute(text("COMMIT;"))

results = op.get_bind().execute(text("""
select sup.id, min(so.order_date) from sales_order so, supplier sup,
Expand Down
Loading

0 comments on commit 7375424

Please sign in to comment.