Beispiel #1
0
def activate_basic_check_credit_rules():
    """
    Issues function calls to activate check credit rules, below.
        These rules are executed not now, but on commits
        Order is irrelevant - determined by system based on dependency analysis
        Their inclusion in classes is for doc / convenience, no semantics

    These rules apply to all transactions (automatic re-use), eg.
    * place order
    * change Order Detail product, quantity
    * add/delete Order Detail
    * ship / unship order
    * delete order
    * move order to new customer, etc
    """

    def units_in_stock(row: Product, old_row: Product, logic_row: LogicRow):
        result = row.UnitsInStock - (row.UnitsShipped - old_row.UnitsShipped)
        return result

    def congratulate_sales_rep(row: Order, old_row: Order, logic_row: LogicRow):
        if logic_row.ins_upd_dlt == "ins" or True:  # logic engine fills parents for insert
            sales_rep = row.SalesRep  # type : Employee
            if sales_rep is None:
                logic_row.log("no salesrep for this order")
            else:
                logic_row.log(f'Hi, {sales_rep.Manager.FirstName}, congratulate {sales_rep.FirstName} on their new order')

    Rule.constraint(validate=Customer,
                    as_condition=lambda row: row.Balance <= row.CreditLimit,
                    error_msg="balance ({row.Balance}) exceeds credit ({row.CreditLimit})")
    Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountTotal,
             where=lambda row: row.ShippedDate is None)  # *not* a sql select sum...

    Rule.sum(derive=Order.AmountTotal, as_sum_of=OrderDetail.Amount)

    Rule.formula(derive=OrderDetail.Amount, as_expression=lambda row: row.UnitPrice * row.Quantity)
    Rule.copy(derive=OrderDetail.UnitPrice, from_parent=Product.UnitPrice)

    Rule.formula(derive=OrderDetail.ShippedDate, as_exp="row.OrderHeader.ShippedDate")

    Rule.sum(derive=Product.UnitsShipped, as_sum_of=OrderDetail.Quantity,
             where="row.ShippedDate is not None")
    Rule.formula(derive=Product.UnitsInStock, calling=units_in_stock)

    Rule.commit_row_event(on_class=Order, calling=congratulate_sales_rep)

    Rule.count(derive=Customer.UnpaidOrderCount, as_count_of=Order,
             where=lambda row: row.ShippedDate is None)  # *not* a sql select sum...

    Rule.count(derive=Customer.OrderCount, as_count_of=Order)
Beispiel #2
0
def declare_logic():
    """
    Issues function calls to activate rules for check credit (etc), below.
        These rules are executed not now, but on commits
        Order is irrelevant - determined by system based on dependency analysis
        Their inclusion in classes is for doc / convenience, no semantics

    These rules apply to all transactions (automatic re-use), eg.
    * place order
    * change Order Detail product, quantity
    * add/delete Order Detail
    * ship / unship order
    * delete order
    * move order to new customer, etc

    Activate rules like this

        LogicBank.activate(session=session, activator=declare_logic)
    """

    def congratulate_sales_rep(row: Order, old_row: Order, logic_row: LogicRow):
        if logic_row.ins_upd_dlt == "ins":  # logic engine fills parents for insert
            sales_rep = row.SalesRep  # type : Employee
            if sales_rep is None:
                logic_row.log("no salesrep for this order")
            else:
                logic_row.log(f'Hi, {sales_rep.Manager.FirstName}, congratulate {sales_rep.FirstName} on their new order')

    Rule.constraint(validate=Customer,
                    as_condition=lambda row: row.Balance <= row.CreditLimit,
                    error_msg="balance ({row.Balance}) exceeds credit ({row.CreditLimit})")
    Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountTotal,
             where=lambda row: row.ShippedDate is None)  # *not* a sql select sum...

    Rule.sum(derive=Order.AmountTotal, as_sum_of=OrderDetail.Amount)

    Rule.formula(derive=OrderDetail.Amount, as_expression=lambda row: row.UnitPrice * row.Quantity)
    Rule.copy(derive=OrderDetail.UnitPrice, from_parent=Product.UnitPrice)

    Rule.commit_row_event(on_class=Order, calling=congratulate_sales_rep)

    Rule.formula(derive=OrderDetail.ShippedDate, as_exp="row.OrderHeader.ShippedDate")

    def units_in_stock(row: Product, old_row: Product, logic_row: LogicRow):
        result = row.UnitsInStock - (row.UnitsShipped - old_row.UnitsShipped)
        return result
    Rule.sum(derive=Product.UnitsShipped, as_sum_of=OrderDetail.Quantity,
             where="row.ShippedDate is not None")
    Rule.formula(derive=Product.UnitsInStock, calling=units_in_stock)

    Rule.count(derive=Customer.UnpaidOrderCount, as_count_of=Order,
             where=lambda row: row.ShippedDate is None)  # *not* a sql select sum...

    Rule.count(derive=Customer.OrderCount, as_count_of=Order)

    Rule.constraint(validate=OrderClass,
                    as_condition=lambda row: row.Id <= 99999,
                    error_msg="Test constraint for className <> tableName")

    Rule.constraint(validate=Employee,
                    as_condition=lambda row: row.IsCommissioned == 1 or row.order_count == 0,
                    error_msg="{row.LastName} is not commissioned - cannot have orders")

    Rule.count(derive=Employee.order_count, as_count_of=Order)

    def raise_over_20_percent(row: Employee, old_row: Employee, logic_row: LogicRow):
        if logic_row.ins_upd_dlt == "upd" and row.Salary != old_row.Salary:
            return row.Salary >= Decimal('1.20') * old_row.Salary
        else:
            return True

    Rule.constraint(validate=Employee,
                    calling=raise_over_20_percent,
                    error_msg="{row.LastName} needs a more meaningful raise")

    def audit_by_event(row: Employee, old_row: Employee, logic_row: LogicRow):
        tedious = False  # tedious code to repeat for every audited class
        if tedious:      # see instead the following rule extension - nw_copy_row
            if logic_row.are_attributes_changed([Employee.Salary, Employee.Title]):
                copy_to_logic_row = logic_row.new_logic_row(EmployeeAudit)
                copy_to_logic_row.link(to_parent=logic_row)
                copy_to_logic_row.set_same_named_attributes(logic_row)
                copy_to_logic_row.insert(reason="Manual Copy " + copy_to_logic_row.name)  # triggers rules...
                # logic_row.log("audit_by_event (Manual Copy) complete")

    Rule.commit_row_event(on_class=Employee, calling=audit_by_event)

    """ also provided in system version
    RuleExtension.copy(copy_from=Employee,
                       copy_to=EmployeeAudit,
                       copy_when=lambda logic_row: logic_row.are_attributes_changed([Employee.Salary, Employee.Title]))
    """

    NWRuleExtension.nw_copy_row(copy_from=Employee,
                                copy_to=EmployeeAudit,
                                copy_when=lambda logic_row:
                                    logic_row.are_attributes_changed([Employee.Salary, Employee.Title]))

    def handle_all(logic_row: LogicRow):
        row = logic_row.row
        if logic_row.ins_upd_dlt == "ins" and hasattr(row, "CreatedOn"):
            row.CreatedOn = datetime.datetime.now()
            logic_row.log("early_row_event_all_classes - handle_all sets 'Created_on"'')

    Rule.early_row_event_all_classes(early_row_event_all_classes=handle_all)