diff --git a/package-lock.json b/package-lock.json index 94143f4..b9d40d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -791,7 +791,6 @@ "version": "7.26.10", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -3008,7 +3007,6 @@ "node_modules/@types/node": { "version": "22.13.14", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.20.0" } @@ -3088,7 +3086,6 @@ "version": "8.28.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.28.0", "@typescript-eslint/types": "8.28.0", @@ -3306,7 +3303,6 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3654,7 +3650,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -4422,7 +4417,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -4501,7 +4495,6 @@ "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -5954,7 +5947,6 @@ "version": "29.7.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -8024,7 +8016,6 @@ "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -8883,7 +8874,6 @@ "version": "10.9.2", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -9058,7 +9048,6 @@ "node_modules/typescript": { "version": "5.8.2", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/src/TemplateArchiveProcessor.ts b/src/TemplateArchiveProcessor.ts index 3fd8f56..69652d0 100644 --- a/src/TemplateArchiveProcessor.ts +++ b/src/TemplateArchiveProcessor.ts @@ -53,6 +53,25 @@ export class TemplateArchiveProcessor { this.template = template; } + /** + * Resolves the logic entry point from compiled code + * @param {Record} compiledCode - the compiled code map + * @returns {string} the entry point key + */ + private resolveLogicEntryPoint(compiledCode: Record): string { + const entryPoint = Object.keys(compiledCode).find( + key => key.startsWith('logic/') && + key.split('/').length === 2 && + !key.includes('generated/') && + key.endsWith('.ts') && + compiledCode[key].code !== undefined + ); + if (!entryPoint) { + throw new Error('Could not find compiled logic entry point'); + } + return entryPoint; + } + /** * Drafts a template by merging it with data * @param {any} data the data to merge with the template @@ -111,13 +130,13 @@ export class TemplateArchiveProcessor { const result = compiler.compile(code); compiledCode[tsFile.getIdentifier()] = result; } - // console.log(compiledCode['logic/logic.ts'].code); + const entryPoint = this.resolveLogicEntryPoint(compiledCode); const evaluator = new JavaScriptEvaluator(); const evalResponse = await evaluator.evalDangerously( { templateLogic: true, verbose: false, functionName: 'trigger', - code: compiledCode['logic/logic.ts'].code, // TODO DCS - how to find the code to run? + code: compiledCode[entryPoint].code, argumentNames: ['data', 'request', 'state'], arguments: [data, request, state, currentTime, utcOffset] }); @@ -160,13 +179,13 @@ export class TemplateArchiveProcessor { const result = compiler.compile(code); compiledCode[tsFile.getIdentifier()] = result; } - // console.log(compiledCode['logic/logic.ts'].code); + const entryPoint = this.resolveLogicEntryPoint(compiledCode); const evaluator = new JavaScriptEvaluator(); const evalResponse = await evaluator.evalDangerously( { templateLogic: true, verbose: false, functionName: 'init', - code: compiledCode['logic/logic.ts'].code, // TODO DCS - how to find the code to run? + code: compiledCode[entryPoint].code, argumentNames: ['data'], arguments: [data, currentTime, utcOffset] }); diff --git a/test/TemplateArchiveProcessor.test.ts b/test/TemplateArchiveProcessor.test.ts index c82026b..671fd54 100644 --- a/test/TemplateArchiveProcessor.test.ts +++ b/test/TemplateArchiveProcessor.test.ts @@ -100,4 +100,58 @@ describe('template archive processor', () => { // the events should have been emitted expect(payload.events[0].penaltyCalculated).toBe(true); }); -}); + + test('should find entry point with non-standard logic filename', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const compiledCode: Record = { + 'logic/mycontract.ts': { code: 'compiled js code' }, + 'logic/README.md': { code: undefined }, + 'logic/generated/types.ts': { code: 'generated code' }, + }; + const entryPoint = Object.keys(compiledCode).find( + key => key.startsWith('logic/') && + key.split('/').length === 2 && + !key.includes('generated/') && + key.endsWith('.ts') && + compiledCode[key].code !== undefined + ); + expect(entryPoint).toBe('logic/mycontract.ts'); + }); + + test('should not select generated files or non-ts files as entry point', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const compiledCode: Record = { + 'logic/README.md': { code: undefined }, + 'logic/generated/io.clause.latedeliveryandpenalty@0.1.0.ts': { code: 'generated code' }, + 'logic/generated/concerto.ts': { code: 'generated code' }, + 'logic/mycontract.ts': { code: 'compiled js code' }, + }; + const entryPoint = Object.keys(compiledCode).find( + key => key.startsWith('logic/') && + key.split('/').length === 2 && + !key.includes('generated/') && + key.endsWith('.ts') && + compiledCode[key].code !== undefined + ); + // should skip README.md and all generated/ files + expect(entryPoint).toBe('logic/mycontract.ts'); + expect(entryPoint).not.toContain('generated'); + expect(entryPoint).not.toBe('logic/README.md'); + }); + + test('should throw when no valid entry point exists', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const compiledCode: Record = { + 'logic/README.md': { code: undefined }, + 'logic/generated/types.ts': { code: 'generated code' }, + }; + const entryPoint = Object.keys(compiledCode).find( + key => key.startsWith('logic/') && + key.split('/').length === 2 && + !key.includes('generated/') && + key.endsWith('.ts') && + compiledCode[key].code !== undefined + ); + expect(entryPoint).toBeUndefined(); + }); +}); \ No newline at end of file diff --git a/test/archives/latedeliveryandpenalty-customlogic/README.md b/test/archives/latedeliveryandpenalty-customlogic/README.md new file mode 100644 index 0000000..a281947 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/README.md @@ -0,0 +1,7 @@ + +# Clause Template: Late Delivery And Penalty + +## Sample + +Late Delivery and Penalty. In case of delayed delivery except for Force Majeure cases, the Seller shall pay to the Buyer for every 2 days of delay penalty amounting to 10.5% of total value of the Equipment whose delivery has been delayed. Any fractional part of a day is to be considered a full day. The total amount of penalty shall not, however, exceed 55% of the total value of the Equipment involved in late delivery. If the delay is more than 15 days, the Buyer is entitled to terminate this Contract. + diff --git a/test/archives/latedeliveryandpenalty-customlogic/logic/README.md b/test/archives/latedeliveryandpenalty-customlogic/logic/README.md new file mode 100644 index 0000000..7cb8529 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/logic/README.md @@ -0,0 +1,25 @@ +# Introduction + +This is a sample Accord Project template that includes logic for the template written in TypeScript. + +# Template Model + +The data model for the template defines the structure of the data for the contract (a "clause" in this case). +The template concept has the `@template` annotation. + +The template model also defines the request and response types for the template logic. + +The template model may optionally also define a state type for the template logic, for templates that support state. + +# Template Logic + +To write your template logic you should first generate the TypeScript source code for the template +using the `concerto compile --model ./model/model.cto --target typescript --output logic/generated` CLI command. + +You can then define and export the template logic class, which should implement the `TemplateLogic` interface, +implementing the trigger method and optionally the init method. + +## Current Limitations + +1. All template logic must be written in TypeScript and in a single file called logic.ts within the logic folder of the template +2. You cannot import third-party modules into your template logic diff --git a/test/archives/latedeliveryandpenalty-customlogic/logic/generated/concerto.decorator@1.0.0.ts b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/concerto.decorator@1.0.0.ts new file mode 100644 index 0000000..f6ea290 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/concerto.decorator@1.0.0.ts @@ -0,0 +1,13 @@ +/* eslint-disable @typescript-eslint/no-empty-object-type*/ +// Generated code for namespace: concerto.decorator@1.0.0 + +// imports +import {IConcept} from './concerto@1.0.0'; + +// interfaces +export interface IDecorator extends IConcept { +} + +export interface IDotNetNamespace extends IDecorator { + namespace: string; +} diff --git a/test/archives/latedeliveryandpenalty-customlogic/logic/generated/concerto.ts b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/concerto.ts new file mode 100644 index 0000000..153630d --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/concerto.ts @@ -0,0 +1,23 @@ +/* eslint-disable @typescript-eslint/no-empty-object-type*/ +// Generated code for namespace: concerto + +// imports + +// interfaces +export interface IConcept { + $class: string; +} + +export interface IAsset extends IConcept { + $identifier: string; +} + +export interface IParticipant extends IConcept { + $identifier: string; +} + +export interface ITransaction extends IConcept { +} + +export interface IEvent extends IConcept { +} diff --git a/test/archives/latedeliveryandpenalty-customlogic/logic/generated/concerto@1.0.0.ts b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/concerto@1.0.0.ts new file mode 100644 index 0000000..c91d4dd --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/concerto@1.0.0.ts @@ -0,0 +1,75 @@ +/* eslint-disable @typescript-eslint/no-unused-vars*/ +// Generated code for namespace: concerto@1.0.0 + +// imports + +// Warning: Beware of circular dependencies when modifying these imports +import type { + ILateDeliveryAndPenaltyState +} from './io.clause.latedeliveryandpenalty@0.1.0'; +import type { + Month, + Day, + TemporalUnit, + IDuration, + PeriodUnit, + IPeriod +} from './org.accordproject.time@0.3.0'; + +// Warning: Beware of circular dependencies when modifying these imports +import type { + IContract, + IClause +} from './org.accordproject.contract@0.2.0'; +import type { + IState +} from './org.accordproject.runtime@0.2.0'; + +// Warning: Beware of circular dependencies when modifying these imports +import type { + IRequest, + IResponse +} from './org.accordproject.runtime@0.2.0'; + +// Warning: Beware of circular dependencies when modifying these imports +import type { + ILateDeliveryAndPenaltyEvent +} from './io.clause.latedeliveryandpenalty@0.1.0'; +import type { + IObligation +} from './org.accordproject.runtime@0.2.0'; + +// interfaces +export interface IConcept { + $class: string; +} + +export type ConceptUnion = ILateDeliveryAndPenaltyState | +IDuration | +IPeriod; + +export interface IAsset extends IConcept { + $identifier: string; +} + +export type AssetUnion = IContract | +IClause | +IState; + +export interface IParticipant extends IConcept { + $identifier: string; +} + +export interface ITransaction extends IConcept { + $timestamp: Date; +} + +export type TransactionUnion = IRequest | +IResponse; + +export interface IEvent extends IConcept { + $timestamp: Date; +} + +export type EventUnion = ILateDeliveryAndPenaltyEvent | +IObligation; diff --git a/test/archives/latedeliveryandpenalty-customlogic/logic/generated/io.clause.latedeliveryandpenalty@0.1.0.ts b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/io.clause.latedeliveryandpenalty@0.1.0.ts new file mode 100644 index 0000000..0867f37 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/io.clause.latedeliveryandpenalty@0.1.0.ts @@ -0,0 +1,39 @@ +/* eslint-disable @typescript-eslint/no-empty-object-type*/ +// Generated code for namespace: io.clause.latedeliveryandpenalty@0.1.0 + +// imports +import {IDuration,TemporalUnit} from './org.accordproject.time@0.3.0'; +import {IClause} from './org.accordproject.contract@0.2.0'; +import {IRequest,IResponse} from './org.accordproject.runtime@0.2.0'; +import {IEvent,IConcept} from './concerto@1.0.0'; + +// interfaces +export interface ITemplateModel extends IClause { + forceMajeure: boolean; + penaltyDuration: IDuration; + penaltyPercentage: number; + capPercentage: number; + termination: IDuration; + fractionalPart: TemporalUnit; +} + +export interface ILateDeliveryAndPenaltyRequest extends IRequest { + forceMajeure: boolean; + agreedDelivery: Date; + deliveredAt?: Date; + goodsValue: number; +} + +export interface ILateDeliveryAndPenaltyResponse extends IResponse { + penalty: number; + buyerMayTerminate: boolean; +} + +export interface ILateDeliveryAndPenaltyEvent extends IEvent { + penaltyCalculated: boolean; +} + +export interface ILateDeliveryAndPenaltyState extends IConcept { + $identifier: string; + count: number; +} diff --git a/test/archives/latedeliveryandpenalty-customlogic/logic/generated/org.accordproject.contract@0.2.0.ts b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/org.accordproject.contract@0.2.0.ts new file mode 100644 index 0000000..e22d7f4 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/org.accordproject.contract@0.2.0.ts @@ -0,0 +1,21 @@ +/* eslint-disable @typescript-eslint/no-empty-object-type*/ +// Generated code for namespace: org.accordproject.contract@0.2.0 + +// imports + +// Warning: Beware of circular dependencies when modifying these imports +import type { + ITemplateModel +} from './io.clause.latedeliveryandpenalty@0.1.0'; +import {IAsset} from './concerto@1.0.0'; + +// interfaces +export interface IContract extends IAsset { + contractId: string; +} + +export interface IClause extends IAsset { + clauseId: string; +} + +export type ClauseUnion = ITemplateModel; diff --git a/test/archives/latedeliveryandpenalty-customlogic/logic/generated/org.accordproject.runtime@0.2.0.ts b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/org.accordproject.runtime@0.2.0.ts new file mode 100644 index 0000000..29eb2d9 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/org.accordproject.runtime@0.2.0.ts @@ -0,0 +1,38 @@ +/* eslint-disable @typescript-eslint/no-empty-object-type*/ +// Generated code for namespace: org.accordproject.runtime@0.2.0 + +// imports + +// Warning: Beware of circular dependencies when modifying these imports +import type { + ILateDeliveryAndPenaltyRequest +} from './io.clause.latedeliveryandpenalty@0.1.0'; + +// Warning: Beware of circular dependencies when modifying these imports +import type { + ILateDeliveryAndPenaltyResponse +} from './io.clause.latedeliveryandpenalty@0.1.0'; +import {IContract} from './org.accordproject.contract@0.2.0'; +import {ITransaction,IEvent,IParticipant,IAsset} from './concerto@1.0.0'; + +// interfaces +export interface IRequest extends ITransaction { +} + +export type RequestUnion = ILateDeliveryAndPenaltyRequest; + +export interface IResponse extends ITransaction { +} + +export type ResponseUnion = ILateDeliveryAndPenaltyResponse; + +export interface IObligation extends IEvent { + $identifier: string; + contract: IContract; + promisor?: IParticipant; + promisee?: IParticipant; + deadline?: Date; +} + +export interface IState extends IAsset { +} diff --git a/test/archives/latedeliveryandpenalty-customlogic/logic/generated/org.accordproject.time@0.3.0.ts b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/org.accordproject.time@0.3.0.ts new file mode 100644 index 0000000..4e60f50 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/logic/generated/org.accordproject.time@0.3.0.ts @@ -0,0 +1,57 @@ +/* eslint-disable @typescript-eslint/no-empty-object-type*/ +// Generated code for namespace: org.accordproject.time@0.3.0 + +// imports +import {IConcept} from './concerto@1.0.0'; + +// interfaces +export enum Month { + January = 'January', + February = 'February', + March = 'March', + April = 'April', + May = 'May', + June = 'June', + July = 'July', + August = 'August', + September = 'September', + October = 'October', + November = 'November', + December = 'December', +} + +export enum Day { + Monday = 'Monday', + Tuesday = 'Tuesday', + Wednesday = 'Wednesday', + Thursday = 'Thursday', + Friday = 'Friday', + Saturday = 'Saturday', + Sunday = 'Sunday', +} + +export enum TemporalUnit { + seconds = 'seconds', + minutes = 'minutes', + hours = 'hours', + days = 'days', + weeks = 'weeks', +} + +export interface IDuration extends IConcept { + amount: number; + unit: TemporalUnit; +} + +export enum PeriodUnit { + days = 'days', + weeks = 'weeks', + months = 'months', + quarters = 'quarters', + years = 'years', +} + +export interface IPeriod extends IConcept { + amount: number; + unit: PeriodUnit; +} diff --git a/test/archives/latedeliveryandpenalty-customlogic/logic/mycontract.ts b/test/archives/latedeliveryandpenalty-customlogic/logic/mycontract.ts new file mode 100644 index 0000000..a3ae6a8 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/logic/mycontract.ts @@ -0,0 +1,54 @@ +// import { EngineResponse, TemplateLogic } from "../../../../src/slc/SmartLegalContract"; +import { ILateDeliveryAndPenaltyState, ILateDeliveryAndPenaltyRequest, ILateDeliveryAndPenaltyResponse, ILateDeliveryAndPenaltyEvent, ITemplateModel } from "./generated/io.clause.latedeliveryandpenalty@0.1.0"; +// demo utility function +function calc(input: number) : number { + const result = input * 2.5; + return result; +} + +// @ts-expect-error EngineResponse is imported by the runtime +interface LateDeliveryContractResponse extends EngineResponse { + result: ILateDeliveryAndPenaltyResponse; + state: object; + events: object[]; +} + +// sample contract logic that is stateless +// - no init method +// @ts-expect-error TemplateLogic is imported by the runtime +class LateDeliveryLogic extends TemplateLogic { + // @ts-expect-error InitResponse is imported by the runtime + async init(data: ITemplateModel) : Promise> { + return { + state: { + $class: 'io.clause.latedeliveryandpenalty@0.1.0.LateDeliveryAndPenaltyState', + $identifier: data.$identifier, + count: 0, + } + } + } + async trigger(data: ITemplateModel, request:ILateDeliveryAndPenaltyRequest, state:ILateDeliveryAndPenaltyState) : Promise { + const event:ILateDeliveryAndPenaltyEvent = { + $class: 'io.clause.latedeliveryandpenalty@0.1.0.LateDeliveryAndPenaltyEvent', + $timestamp: new Date(), + penaltyCalculated: true + }; + const newState:ILateDeliveryAndPenaltyState = { + $class: 'io.clause.latedeliveryandpenalty@0.1.0.LateDeliveryAndPenaltyState', + $identifier: state.$identifier, + count: state.count + 1, + } + return { + result: { + penalty: data.penaltyPercentage * calc(request.goodsValue), + buyerMayTerminate: true, + $timestamp: new Date(), + $class: 'io.clause.latedeliveryandpenalty@0.1.0.LateDeliveryAndPenaltyResponse' + }, + events: [event], + state: newState + } + } +} + +export default LateDeliveryLogic; diff --git a/test/archives/latedeliveryandpenalty-customlogic/model/@models.accordproject.org.accordproject.contract@0.2.0.cto b/test/archives/latedeliveryandpenalty-customlogic/model/@models.accordproject.org.accordproject.contract@0.2.0.cto new file mode 100644 index 0000000..e513525 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/model/@models.accordproject.org.accordproject.contract@0.2.0.cto @@ -0,0 +1,32 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +concerto version "^3.0.0" + +namespace org.accordproject.contract@0.2.0 + +/** + * Contract Data + * -- Describes the structure of contracts and clauses + */ + +/* A contract is a asset -- This contains the contract data */ +abstract asset Contract identified by contractId { + o String contractId +} + +/* A clause is an asset -- This contains the clause data */ +abstract asset Clause identified by clauseId { + o String clauseId +} diff --git a/test/archives/latedeliveryandpenalty-customlogic/model/@models.accordproject.org.accordproject.runtime@0.2.0.cto b/test/archives/latedeliveryandpenalty-customlogic/model/@models.accordproject.org.accordproject.runtime@0.2.0.cto new file mode 100644 index 0000000..a313a79 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/model/@models.accordproject.org.accordproject.runtime@0.2.0.cto @@ -0,0 +1,51 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +concerto version "^3.0.0" + +namespace org.accordproject.runtime@0.2.0 + +import org.accordproject.contract@0.2.0.Contract from https://models.accordproject.org/accordproject/contract@0.2.0.cto + +/** + * Runtime API + * -- Describes input and output of calls to a contract's clause + */ + +/* A request is a transaction */ +transaction Request { +} + +/* A response is a transaction */ +transaction Response { +} + +/* An event that represents an obligation that needs to be fulfilled */ +abstract event Obligation identified { + /* A back reference to the governing contract that emitted this obligation */ + --> Contract contract + + /* The party that is obligated */ + --> Participant promisor optional + + /* The party that receives the performance */ + --> Participant promisee optional + + /* The time before which the obligation is fulfilled */ + o DateTime deadline optional +} + +/* A contract state is an asset -- The runtime state of the contract */ +asset State { +} diff --git a/test/archives/latedeliveryandpenalty-customlogic/model/@models.accordproject.org.time@0.3.0.cto b/test/archives/latedeliveryandpenalty-customlogic/model/@models.accordproject.org.time@0.3.0.cto new file mode 100644 index 0000000..819b858 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/model/@models.accordproject.org.time@0.3.0.cto @@ -0,0 +1,85 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +concerto version "^3.0.0" + +namespace org.accordproject.time@0.3.0 + +/** + * Months of the year + */ +enum Month { + o January + o February + o March + o April + o May + o June + o July + o August + o September + o October + o November + o December +} + +/** + * Days of the week + */ +enum Day { + o Monday + o Tuesday + o Wednesday + o Thursday + o Friday + o Saturday + o Sunday +} + +/** + * Units for a duration. + */ +enum TemporalUnit { + o seconds + o minutes + o hours + o days + o weeks +} + +/** + * A duration. For example, 6 hours. + */ +concept Duration { + o Long amount + o TemporalUnit unit +} + +/** + * Units for a time period. + */ +enum PeriodUnit { + o days + o weeks + o months + o quarters + o years +} + +/** + * A time period. For example, 2 months. + */ +concept Period { + o Long amount + o PeriodUnit unit +} diff --git a/test/archives/latedeliveryandpenalty-customlogic/model/model.cto b/test/archives/latedeliveryandpenalty-customlogic/model/model.cto new file mode 100644 index 0000000..1b86ada --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/model/model.cto @@ -0,0 +1,99 @@ +namespace io.clause.latedeliveryandpenalty@0.1.0 + +import org.accordproject.time@0.3.0.{Duration, TemporalUnit} from https://models.accordproject.org/time@0.3.0.cto + +import org.accordproject.contract@0.2.0.Clause from https://models.accordproject.org/accordproject/contract@0.2.0.cto +import org.accordproject.runtime@0.2.0.{Request,Response} from https://models.accordproject.org/accordproject/runtime@0.2.0.cto + +/** + * Defines the data model for the LateDeliveryAndPenalty template. + * This defines the structure of the abstract syntax tree that the parser for the template + * must generate from input source text. + */ +@template +asset TemplateModel extends Clause { + /** + * Does the clause include a force majeure provision? + */ + o Boolean forceMajeure + + /** + * For every penaltyDuration that the goods are late + */ + o Duration penaltyDuration + + /** + * Seller pays the buyer penaltyPercentage % of the value of the goods + */ + o Double penaltyPercentage + + /** + * Up to capPercentage % of the value of the goods + */ + o Double capPercentage + + /** + * If the goods are >= termination late then the buyer may terminate the contract + */ + o Duration termination + + /** + * Fractional part of a ... is considered a whole ... + */ + o TemporalUnit fractionalPart +} + +/** + * Defines the input data required by the template + */ +transaction LateDeliveryAndPenaltyRequest extends Request { + + /** + * Are we in a force majeure situation? + */ + o Boolean forceMajeure + + /** + * What was the agreed delivery date for the goods? + */ + o DateTime agreedDelivery + + /** + * If the goods have been delivered, when where they delivered? + */ + o DateTime deliveredAt optional + + /** + * What is the value of the goods? + */ + o Double goodsValue +} + +/** + * Defines the output data for the template + */ +transaction LateDeliveryAndPenaltyResponse extends Response { + /** + * The penalty to be paid by the seller + */ + o Double penalty + + /** + * Whether the buyer may terminate the contract + */ + o Boolean buyerMayTerminate +} + +/** + * Define an event that is emitted by the template + */ +event LateDeliveryAndPenaltyEvent { + o Boolean penaltyCalculated +} + +/** + * Defines the state of the template + */ +concept LateDeliveryAndPenaltyState identified { + o Integer count +} diff --git a/test/archives/latedeliveryandpenalty-customlogic/package.json b/test/archives/latedeliveryandpenalty-customlogic/package.json new file mode 100644 index 0000000..82e7e70 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/package.json @@ -0,0 +1,10 @@ +{ + "name": "latedeliveryandpenalty-customlogic", + "version": "0.0.1", + "description": "Late Delivery and Penalty. In case of delayed delivery except for Force Majeure cases, the Seller shall pay to the Buyer for every 9 DAY of delay penalty amounting to 7.0% of the total value of the Equipment whose delivery has been delayed. Any fractional part of a DAY is to be considered a full DAY. The total amount of penalty shall not however, exceed 2.0% of the total value of the Equipment involved in late delivery. If the delay is more than 2 WEEK, the Buyer is entitled to terminate this Contract.", + "accordproject": { + "runtime": "typescript", + "template": "clause", + "cicero": "^0.25.0" + } +} diff --git a/test/archives/latedeliveryandpenalty-customlogic/request.json b/test/archives/latedeliveryandpenalty-customlogic/request.json new file mode 100644 index 0000000..86d66a7 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/request.json @@ -0,0 +1,7 @@ +{ + "$class": "io.clause.latedeliveryandpenalty@0.1.0.LateDeliveryAndPenaltyRequest", + "forceMajeure": false, + "agreedDelivery": "December 17, 2017 03:24:00", + "deliveredAt": null, + "goodsValue": 200.00 +} diff --git a/test/archives/latedeliveryandpenalty-customlogic/text/grammar.tem.md b/test/archives/latedeliveryandpenalty-customlogic/text/grammar.tem.md new file mode 100644 index 0000000..a98a724 --- /dev/null +++ b/test/archives/latedeliveryandpenalty-customlogic/text/grammar.tem.md @@ -0,0 +1,7 @@ +Late Delivery and Penalty +---- +In case of delayed delivery{{#if forceMajeure}} except for Force Majeure cases,{{/if}} the Seller shall pay to the Buyer for every {{penaltyDuration}} of delay penalty amounting to {{penaltyPercentage}}% of the total value of the Equipment whose delivery has been delayed. + +1. Any fractional part of a {{fractionalPart}} is to be considered a full {{fractionalPart}}. +1. The total amount of penalty shall not however, exceed {{capPercentage}}% of the total value of the Equipment involved in late delivery. +1. If the delay is more than {{termination}}, the Buyer is entitled to terminate this Contract.