示例#1
0
def declare_logic():
    def requires_admin(row):
        if g.user.id == 0:
            return True
        return False

    Rule.constraint(validate=User, error_msg="Can't change User", as_condition=requires_admin)
示例#2
0
def declare_logic():

    Rule.parent_check(validate=Child, error_msg="no parent", enable=True)

    Rule.constraint(validate=Parent,
                    as_condition=lambda row: row.parent_attr_1 != "hello",
                    error_msg="Ensure other tables ok")
示例#3
0
    def not_loaded(self):
        Rule.formula(derive="Tbl.ColA",  # or, calling=compute_amount)
                     as_exp="row.ColB + row.ColC")

        Rule.formula(derive="Tbl.ColB",  # or, calling=compute_amount)
                     as_exp="row.ColC")

        Rule.formula(derive="Tbl.ColC",  # or, calling=compute_amount)
                     as_exp="row.ColD")

        Rule.formula(derive="Tbl.ColD",  # or, calling=compute_amount)
                     as_exp="row.ColE")

        Rule.formula(derive="Tbl.ColE",  # or, calling=compute_amount)
                     as_exp="xxx")
def declare_logic():

    Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountOwed)

    Rule.formula(derive=Order.AmountOwed,
                 as_expression=lambda row: row.AmountTotal - row.AmountPaid)
    Rule.sum(derive=Order.AmountPaid,
             as_sum_of=PaymentAllocation.AmountAllocated)

    Rule.formula(
        derive=PaymentAllocation.AmountAllocated,
        as_expression=lambda row: min(Decimal(row.Payment.AmountUnAllocated),
                                      Decimal(row.Order.AmountOwed)))

    Rule.early_row_event(on_class=Payment, calling=allocate_payment)
    """
示例#5
0
def declare_logic():

    Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountOwed)

    Rule.formula(derive=Order.AmountOwed,
                 as_expression=lambda row: row.AmountTotal - row.AmountPaid)
    Rule.sum(derive=Order.AmountPaid,
             as_sum_of=PaymentAllocation.AmountAllocated)

    Rule.formula(
        derive=PaymentAllocation.AmountAllocated,
        as_expression=lambda row: min(Decimal(row.Payment.AmountUnAllocated),
                                      Decimal(row.Order.AmountOwed)))

    RuleExtension.allocate(provider=Payment,
                           recipients=unpaid_orders,
                           creating_allocation=PaymentAllocation)
    """
示例#6
0
    def load_rules(self):

        def my_early_event(row, old_row, logic_row):
            logic_row.log("early event for *all* tables - good breakpoint, time/date stamping, etc")

        def check_balance(row: Customer, old_row, logic_row) -> bool:
            """
            Not used... illustrate function alternative (e.g., more complex if/else logic)
            specify rule with `calling=check_balance` (instead of as_condition)
            """
            return row.Balance <= row.CreditLimit

        def compute_amount(row: OrderDetail, old_row, logic_row):
            return row.UnitPrice * row.Quantity

        Rule.formula(derive="OrderDetail.Amount", calling=compute_amount)

        Rule.formula(derive="OrderDetail.Amount", calling=lambda Customer: Customer.Quantity * Customer.UnitPrice)

        Rule.early_row_event(on_class="*", calling=my_early_event)  # just for debug

        Rule.constraint(validate="Customer", calling=check_balance,
                        error_msg="balance ({row.Balance}) exceeds credit ({row.CreditLimit})")
示例#7
0
def declare_logic():
    """
    Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountOwed)

    Rule.formula(derive=Order.AmountOwed, as_expression=lambda row: row.AmountTotal - row.AmountPaid)
    Rule.sum(derive=Order.AmountPaid, as_sum_of=PaymentAllocation.AmountAllocated)

    Rule.formula(derive=PaymentAllocation.AmountAllocated, as_expression=lambda row:
        min(Decimal(row.Payment.AmountUnAllocated), Decimal(row.Order.AmountOwed)))

    Rule.early_row_event(on_class=Payment, calling=allocate_payment)
    """
    Rule.constraint(validate=StoreModel,
                    as_condition=lambda row: 'X' not in row.name,
                    error_msg="Store Names({row.name}) should not  contain X")
    Rule.count(StoreModel.item_count, as_count_of=ItemModel)
    Rule.parent_check(validate=ItemModel, error_msg="no parent", enable=True)
示例#8
0
def declare_logic():
    """
    activate, then rules applied on commit

    automatically invoked, ordered and optimized
    """

    explore_rules = False   # set True to explore rules
    if explore_rules:
        Rule.constraint(validate=Customer,
                        error_msg="balance ({row.Balance}) exceeds 2000)",
                        as_condition=lambda row: row.Balance <= 2000)

        Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountTotal)

    explore_extensibility = False  # set True to explore extensibility
    if explore_extensibility:

        def follow_up(row: Order, old_row: Order, logic_row: LogicRow):
            if logic_row.ins_upd_dlt == "upd":
                if logic_row.row.AmountTotal < logic_row.old_row.AmountTotal:
                    print("\nStub: send email to sales manager to follow up\n")

        Rule.commit_row_event(on_class=Order, calling=follow_up)
示例#9
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)
示例#10
0
def activate_basic_rules():

    def transfer_funds(row: TRANSFERFUND, old_row: TRANSFERFUND, logic_row: LogicRow):
        if logic_row.ins_upd_dlt == "ins" or True:  # logic engine fills parents for insert
            logic_row.log("Transfer from source to target")
            fromCustNum = row.FromCustNum
            toCustNum = row.ToCustNum
            acctNum = row.FromAcct
            trans_date = datetime.datetime(2020, 10, 1)
            transferAmt = row.TransferAmt
            transID = row.TransId
            # need to lookup the From Acct to see if it is checking or savings - that way we can reverse the flow
            deposit = models.SAVINGSTRANS(TransId=transID, CustNum=toCustNum, AcctNum=acctNum, DepositAmt=transferAmt, WithdrawlAmt=0,
                                          TransDate=trans_date)
            logic_row.insert("Deposit to savings", deposit)
            withdrawl = models.CHECKINGTRANS(TransId=transID, CustNum=fromCustNum, AcctNum=acctNum,
                                             DepositAmt=0, WithdrawlAmt=transferAmt, TransDate=trans_date)
            logic_row.insert("Withdraw from CHECKINGTRANS", withdrawl)

    Rule.sum(derive=CHECKING.Deposits, as_sum_of=CHECKINGTRANS.DepositAmt)
    Rule.sum(derive=CHECKING.Withdrawls, as_sum_of=CHECKINGTRANS.WithdrawlAmt)
    Rule.formula(derive=CHECKING.AvailableBalance, as_expression=lambda  row: row.Deposits - row.Withdrawls)
    Rule.count(derive=CHECKING.ItemCount, as_count_of=CHECKINGTRANS)

    Rule.sum(derive=CUSTOMER.CheckingAcctBal, as_sum_of=CHECKING.AvailableBalance)
    Rule.sum(derive=CUSTOMER.SavingsAcctBal, as_sum_of=SAVING.AvailableBalance)
    Rule.formula(derive=CUSTOMER.TotalBalance, as_expression=lambda row: row.CheckingAcctBal + row.SavingsAcctBal)
    Rule.constraint(validate=CUSTOMER,
                    as_condition=lambda row: row.CheckingAcctBal >= 0,
                    error_msg="Your Checking balance of ({row.CheckingAcctBal}) is less than 0)")
    Rule.constraint(validate=CUSTOMER,
                    as_condition=lambda row: row.SavingsAcctBal >= 0,
                    error_msg="Your Savings balance of ({row.SavingsAcctBal}) is less than 0)")

    Rule.sum(derive=SAVING.Withdrawls, as_sum_of=SAVINGSTRANS.WithdrawlAmt)
    Rule.sum(derive=SAVING.Deposits, as_sum_of=SAVINGSTRANS.DepositAmt)
    Rule.formula(derive=SAVING.AvailableBalance, as_expression=lambda row: row.Deposits - row.Withdrawls)
    Rule.count(derive=SAVING.ItemCount, as_count_of=SAVINGSTRANS)

    Rule.formula(derive=CHECKINGTRANS.Total, as_expression=lambda row: row.DepositAmt - row.WithdrawlAmt)
    Rule.formula(derive=SAVINGSTRANS.Total, as_expression=lambda row: row.DepositAmt - row.WithdrawlAmt)

    Rule.commit_row_event(on_class=TRANSFERFUND, calling=transfer_funds)
示例#11
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)
示例#12
0
    def not_loaded(self):
        Rule.constraint(validate="AbUser",  # table is ab_user
                        calling=lambda row: row.username != "no_name")

        Rule.count(derive=Customer.OrderCount, as_count_of=Order,
                   where="ShippedDate not None")