Feedback on Rental Property Rental Agreement

@fabio.tudone Just some feedback on the Rental Smart Contract:

This system is fully supported with Node, Java and Daml, and I followed the instructions at:

The instructions initially worked through Terminals [1…3], however the process failed at:

$ cd ui/
$ yarn start

The error from this was:

sh: react-scripts: command not found but there was more than that, however I did not think to save it, before solving it.

yarn start --errata

yarn_start_runs_but_errata_2021-04-13.daml (18.0 KB)

Solution, referring to sh: react-scripts

$ rm -f yarn.lock

$ sudo npm upgrade  <- Should not use 'sudo' with Node, however Node.js
& NPM on Ubuntu by default does something ridiculously daft with the base
install, so you *have* to use 'sudo' on 'npm' commands due to /usr/bin/npm/node
permissions or else 'npm' will not execute for you 8-(

$ sudo npm install -g npm@latest
$ sudo npm install -g npm@7.9.0
$ sudo npm install --force  <- Unsafe
$ sudo npm audit fix --force  <- Unsafe
$ yarn start
Compiled successfully!

You can now view ui in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://192.168.1.150:3000

Note that the development build is not optimized.
To create a production build, use npm run build.

Login into to http://localhost:3000/properties as the Authority party and from there, the user can do nothing further.

Is this due to the stated limit of:

At present only two choices are implemented and the rest are left out as an exercise to the reader :wink: : Authority registers a property and Landlord puts it to rent; the rest of the steps have to be carried out using the DAML Navigator UI.

Or is there a further issue with my install? I want to get it working so I can extend the contract to include Maintenance requests and periodic inspections ← a pet hate of mine :angry:

2 Likes

Hi @quidagis and thanks for the feedback!

The instructions initially worked through Terminals [1…3], however the process failed at:

$ cd ui/
$ yarn start

The error from this was:

sh: react-scripts: command not found but there was more than that, however I did not think to save it, before solving it.

README.md (now updated) was missing a step there, it seems that running yarn before yarn start is enough to download the dependencies, including react-scripts.

Let me know if that works for you too.

Login into to http://localhost:3000/properties as the Authority party and from there, the user can do nothing further.

All actions can be carried out through the Daml navigator but two of them (the ones mentioned in the post) are also supported by the React UI. I have updated the README.md with a short explanation about them.

I have also fixed an issue with the JSON request format there.

I want to get it working so I can extend the contract to include Maintenance requests and periodic inspections ← a pet hate of mine :angry:

Yo’re probably in good company :slight_smile:

By the way, I still have an item in my “want to do” list about upgrading Daml Rental to the latest Daml version, I hope to get around to doing it soon.

In addition to discussing them in the forum, if you find room for improvements (or bugfixes), feel also free to open GitHub issues and/or send PRs!

2 Likes

This was your first post!! Welcome to the churn :joy:

Re the update instructions, will do. I’ll run it again in the morning, and update you. It’s a great contract with significant scope to morph into other use cases.

I upgraded my Daml to 1.12.1.snapshot last week, no issues reported, but I did notice that your contract was squawking about Daml 1.11.1 :sunglasses:

Again, nice job!

3 Likes

This was your first post!! Welcome to the churn

Oh that’s true, shame on me :joy:

Again, nice job!

Thank you and let me/us know how things are going, both with running Daml Rental and with your additions!

2 Likes

I’ll give you the short version of how I got this to work:

# Remove all current NPM packages, globally, from the system
$ npm ls -gp --depth=0 | awk -F/node_modules/ '{print $2}' | grep -vE '^(npm|)$' | xargs -r npm -g rm
$ npm ls
/home/quid
└── (empty)
$ git clone https://github.com/circlespainter/daml-rental.git
# Follow the instructions as per the README.md

Critical point, in relation to TERMINAL 4:

$ cd ui
$ yarn
$ yarn start
# There will be a warning:
# Browserslist: caniuse-lite is outdated. Please run next command `yarn upgrade`
# **DO NOT UPGRADE**, the 'daml-rental' app will break
Error from 'yarn upgrade'
#### Remove NPM Modules Globally

quid ~ $ npm ls -gp --depth=0 | awk -F/node_modules/ '{print $2}' | grep -vE '^(npm|)$' | xargs -r npm -g rm
quid ~ $ npm ls
/home/quid
└── (empty)
$ cd ~/Git
$ rm -rf daml-rental
rm: cannot remove 'daml-rental/ui/node_modules/@typescript-eslint/typescript-estree/node_modules/.bin/semver': Permission denied
rm: cannot remove 'daml-rental/ui/node_modules/@babel/plugin-transform-runtime/node_modules/.bin/semver': Permission denied
rm: cannot remove 'daml-rental/ui/node_modules/webpack/node_modules/.bin/acorn': Permission denied
rm: cannot remove 'daml-rental/ui/node_modules/react-scripts/node_modules/@babel/core/node_modules/.bin/semver': Permission denied
rm: cannot remove 'daml-rental/ui/node_modules/babel-preset-react-app/node_modules/.bin/semver': Permission denied
rm: cannot remove 'daml-rental/ui/node_modules/resolve-url-loader/node_modules/.bin/json5': Permission denied
rm: cannot remove 'daml-rental/ui/node_modules/fork-ts-checker-webpack-plugin/node_modules/.bin/semver': Permission denied
$ sudo rm -rf daml-rental
$ ls daml-rental
ls: cannot access 'daml-rental': No such file or directory

## Reinstall Daml Rental

$ git clone https://github.com/circlespainter/daml-rental.git
Cloning into 'daml-rental'...
remote: Enumerating objects: 135, done.
remote: Counting objects: 100% (135/135), done.
remote: Compressing objects: 100% (101/101), done.
remote: Total 135 (delta 48), reused 102 (delta 25), pack-reused 0
Receiving objects: 100% (135/135), 228.83 KiB | 1.05 MiB/s, done.
Resolving deltas: 100% (48/48), done.
$ cd daml-rental
$ clear && ls -al
total 40
drwxrwxr-x  6 quid quid 4096 Apr 14 13:55 .
drwxrwxr-x 12 quid quid 4096 Apr 14 13:55 ..
drwxrwxr-x  3 quid quid 4096 Apr 14 13:55 cleanup-trigger
drwxrwxr-x  8 quid quid 4096 Apr 14 13:55 .git
-rw-rw-r--  1 quid quid   48 Apr 14 13:55 .gitignore
drwxrwxr-x  4 quid quid 4096 Apr 14 13:55 ledger
-rw-rw-r--  1 quid quid  639 Apr 14 13:55 LICENSE
-rw-rw-r--  1 quid quid 5019 Apr 14 13:55 README.md
drwxrwxr-x  4 quid quid 4096 Apr 14 13:55 ui

## [TERMINAL 4]

quid ~/Git/daml-rental $ cd ui
quid ~/Git/daml-rental/ui $ yarn
yarn install v1.22.5
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@2.1.2: The platform "linux" is incompatible with this module.
info "fsevents@2.1.2" is an optional dependency and failed compatibility check. Excluding it from installation.
info fsevents@1.2.9: The platform "linux" is incompatible with this module.
info "fsevents@1.2.9" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning " > @testing-library/user-event@7.2.1" has unmet peer dependency "@testing-library/dom@>=5".
warning " > material-table@1.56.1" has unmet peer dependency "@date-io/core@^1.3.6".
warning "material-table > @material-ui/pickers@3.2.9" has unmet peer dependency "@date-io/core@^1.3.6".
[4/4] Building fresh packages...
Done in 52.55s.
quid ~/Git/daml-rental/ui $ yarn start 
Starting the development server...

Browserslist: caniuse-lite is outdated. Please run next command `yarn upgrade`

Compiled successfully!

You can now view ui in the browser.

  Local:            http://localhost:3000/
  On Your Network:  http://192.168.1.150:3000/

Note that the development build is not optimized.
To create a production build, use yarn build.

Starting the development server...

$ Ctrl-C
$ yarn upgrade
$ yarn start

## Console Error Output

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
    at new NodeError (node:internal/errors:329:5)
    at validateString (node:internal/validators:129:11)
    at Object.join (node:path:1081:7)
    at noopServiceWorkerMiddleware (/home/quid/Git/daml-rental/ui/node_modules/react-dev-utils/noopServiceWorkerMiddleware.js:14:26)
    at Layer.handle [as handle_request] (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:317:13)
    at /home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:335:12)
    at next (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:275:10)
    at launchEditorMiddleware (/home/quid/Git/daml-rental/ui/node_modules/react-dev-utils/errorOverlayMiddleware.js:20:7)
    at Layer.handle [as handle_request] (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:317:13)
    at /home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:335:12)
    at next (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:275:10)
    at handleWebpackInternalMiddleware (/home/quid/Git/daml-rental/ui/node_modules/react-dev-utils/evalSourceMapMiddleware.js:42:7)
-----

Failed to compile.

## File Error Warning
## I edited Line 67, removed the {}, added (), no change

# File: /home/quid/Git/daml-rental/ui/src/App.tsx

TypeScript error in /home/quid/Git/daml-rental/ui/src/App.tsx(67,15):
No overload matches this call.
  Overload 1 of 2, '(props: { component: ElementType<any>; } & { children: string | number | boolean | {} | ReactElement<any, string | ((props: any) => ReactElement<any, any> | null) | (new (props: any) => Component<...>)> | ReactNodeArray | ReactPortal; disableGutters?: boolean | undefined; fixed?: boolean | undefined; maxWidth?: false | ... 5 more ... | undefined; } & CommonProps<...> & Pick<...>): Element', gave the following error.
    Type 'ReactNode' is not assignable to type 'string | number | boolean | {} | ReactElement<any, string | ((props: any) => ReactElement<any, any> | null) | (new (props: any) => Component<any, any, any>)> | ReactNodeArray | ReactPortal'.
      Type 'undefined' is not assignable to type 'string | number | boolean | {} | ReactElement<any, string | ((props: any) => ReactElement<any, any> | null) | (new (props: any) => Component<any, any, any>)> | ReactNodeArray | ReactPortal'.
  Overload 2 of 2, '(props: DefaultComponentProps<ContainerTypeMap<{}, "div">>): Element', gave the following error.
    Type 'ReactNode' is not assignable to type 'string | number | boolean | {} | ReactElement<any, string | ((props: any) => ReactElement<any, any> | null) | (new (props: any) => Component<any, any, any>)> | ReactNodeArray | ReactPortal'.
      Type 'undefined' is not assignable to type 'string | number | boolean | {} | ReactElement<any, string | ((props: any) => ReactElement<any, any> | null) | (new (props: any) => Component<any, any, any>)> | ReactNodeArray | ReactPortal'.  TS2769

    65 |         <div>
    66 |           <Container maxWidth="xl" className={classes.container}>
  > 67 |               {props.children}
       |               ^
    68 |           </Container>
    69 |         </div>
    70 |     )


## Google Chrome Browser Error Output:

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
    at new NodeError (node:internal/errors:329:5)
    at validateString (node:internal/validators:129:11)
    at Object.join (node:path:1081:7)
    at noopServiceWorkerMiddleware (/home/quid/Git/daml-rental/ui/node_modules/react-dev-utils/noopServiceWorkerMiddleware.js:14:26)
    at Layer.handle [as handle_request] (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:317:13)
    at /home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:335:12)
    at next (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:275:10)
    at launchEditorMiddleware (/home/quid/Git/daml-rental/ui/node_modules/react-dev-utils/errorOverlayMiddleware.js:20:7)
    at Layer.handle [as handle_request] (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:317:13)
    at /home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:335:12)
    at next (/home/quid/Git/daml-rental/ui/node_modules/express/lib/router/index.js:275:10)
    at handleWebpackInternalMiddleware (/home/quid/Git/daml-rental/ui/node_modules/react-dev-utils/evalSourceMapMiddleware.js:42:7)

## EOF

Otherwise, continue as per the instructions and it works great :+1:t2:

For those whom are interested:

Daml Rental app File Structure

daml_rental_fs_using_tree.daml (3.7 MB)

Anyone else who is interested in Rental Contracts and is happy to work together, to help Fabio extend this, please ping me.

Also @fabio.tudone I have forked the project, and submitted a very minor PR. More to follow.

EDIT: I removed the daml-rental-yarn error as a file, and included it as formatted code using the [Hide Details] function. I also went to do the same thing for the daml-rental/tree output but I received a 413 Error size too big from the blog.

2 Likes

I am reading through daml-rental/…/Rental.daml and I note that you seem to use the indentation of 4/8 spaces, not 2/4 as I have seen in most Daml code. As it is all aligned perfectly, it makes no functional difference but from the Daml language POV, is this OK?

I’m happy to do what your existing code does, but just wanted to ask.

From what I can see, the project seems to be driven off the …/ledger/daml/Rental.daml for functional actions but …/ui/src/tables for the presentation actions.

If that is correct, then to add in additional functionality say, a maintenance request by the current Tenant, the place to start would be the Rental.daml? I’ll just copy one of the current Templates and work my way through adding a maint_req in.

1 Like

The Daml compiler doesn’t care about how many spaces as long as:

  • All the code that is part of the same block is indented at the same level, and
  • Nested blocks are indented (at least one space) more than their parent.

So instead of 2/4/6/8 you could go for 1/5/18/19 and that would work just as well. Readers of your code may not be too happy though.

3 Likes

I like to think about the business logic first, so I tend to first model it in Daml and then to think about the UI. This is also made quite easy by Daml Navigator, so my suggestion would be to try and do the same and see if it works for you.

On a bigger project the process is probably more bi-directional, as you’ll have UX-oriented sessions taking the business idea and thinking about user interaction and usability matters, business-oriented sessions thinking about the formal business model (probably directly in Daml) and then engineering work to refine and putting it all together. It is also probably much less linear, perhaps using design thinking techniques to challenge and refine the business idea itself.

1 Like

Makes sense. As a non-Developer / Business type (Currently), in relation to the Daml Rental application, I’d do something similar as to you; model the business logic in Daml, and when it works, or fails less, I’d consider some type of UI front :grinning:

I usually use pseudo-code for any idea, flesh out the usual & critical use cases, then start to code using the language of choice. I did note that Daml removes a lot of those upfront decisions such as do I need to loop here? How do I handle messaging? If it fails, what happens?

Which is very handy and forgiving for a new user.

I am currently making a MaintenanceRequest template, and based on my years of renting I have a solid handle on that actual business process. I’ll do some testing tomorrow and see how it goes, then maybe a PR.

2 Likes

I am adding in another template titled ‘MaintenanceRequest’, and the logic flow from it is initially as follows:

Note: MaintenanceRequest is referred to as: Maint_Req

Process:

  1. Tenant contacts Agency about Maintenance Issue
  2. Agency confirms Maintenance issue
  3. If repair cost < $300, Agency contacts Provider
  4. If repair cost > $300, Agency contacts Landlord
  5. If Landlord approves Repair, Agency contacts Provider
  6. Provider contacts Tenant, arranges Access Time/Date
  7. Repair is actioned
  8. Tenant provides Feedback to Agency
  9. If Good, Agency close Maint_Req, Authorises payment
  10. If Bad, Agency visits Property, inspects, Provider remediates
  11. Agency inspects, closes Maint_Req, authorises payment

I reviewed the existing Rental.daml and
choose the template VisitScheduleRequest.

View 'template VisitScheduleRequest
template VisitScheduleRequest
    with
        -- Signatory
        agency : Party
        visitor : Party
        landlord : Party

        -- Controller
        tenant : Party

        -- Data
        registerId : Text -- Carryover

    where
        -- Agreement
        agreement
            "A request by a visitor to schedule a visit with the tenant"

        signatory
            agency,
            visitor,
            landlord

        controller agency can

            VisitScheduleRequest_Abort : () do return () -- For cleanup trigger

        controller tenant can

            VisitScheduleRequest_Accept : ContractId Visited
                do
                    create Visited with
                        -- Signatory
                        agency,
                            visitor,
                            landlord,

                        -- Data
                            registerId -- Carryover

            VisitScheduleRequest_Reject : () do return ()

Modified it to new terms, but I think it can support almost the same method of making contact; setting a visit time, complete the visit, records the visit.

template MaintenanceRequest
template MaintenanceRequest
    with
        -- Signatory
        landlord : Party
        agency : Party
        provider: Party

        -- Controller
        agency : Party

        -- Data
        registerId : Text -- Carryover

    where
        -- Agreement
        agreement
            "Test"

        signatory
            agency,
            landlord,
            provider

        controller agency can

            MaintenanceRequest_Withdraw : () do return () -- For cleanup trigger

        controller agency can

            MaintenanceRequest_Accept : ContractId Approved
                do
                    create Approved with
                        -- Signatory
                        agency,
                            landlord,
                            provider,

                        -- Controller
                            agency,

                        -- Data
                            registerId -- Carryover

        controller agency can

            MaintenanceRequest_Refuse : ContractId Denied
                do
                    create Denied with
                        -- Signatory
                        agency,
                            landlord,

                        -- Controller
                            agency,

                        -- Data
                            registerId -- Carryover

        controller agency can

            MaintenanceRequest_Schedule : ContractId Scheduled
                do
                    create Scheduled with
                        -- Signatory
                        agency,
                            landlord,
                            provider,

                        -- Controller
                            agency,

                        -- Data
                            registerId -- Carryover

        controller agency can

            MaintenanceRequest_Active : ContractId Active
                do
                    create Active with
                        -- Signatory
                        agency,
                            landlord,
                            provider,

                        -- Controller
                            agency

                        -- Data
                            registerId -- Carryover

        controller agency can

            MaintenanceRequest_Repaired : ContractId Complete -- repair done, not inspected
                do
                    create Complete with
                        -- Signatory
                        agency,
                            landlord,
                            provider,

                        -- Controller
                            agency

                        -- Data
                            registerId -- Carryover

        controller agency can

            MaintenanceRequest_Processed : ContractId Finalised -- repair done, inspected, authorised payment
                do
                    create Finalised with
                        -- Signatory
                        agency,
                            landlord,
                            provider,

                        -- Controller
                            agency

                        -- Data
                            registerId -- Carryover

-- END OF FILE

The current configuration produces this error:

New template error output
... truncated ...
  Bound at: daml/Rental.daml:615:20-25
  daml/Rental.daml:615:20-25
  • In a lambda abstraction
File:     daml/Rental.daml
Hidden:   no
Range:    617:54-617:63
Source:   typecheck
Severity: DsError
Message:  daml/Rental.daml:617:55: error:Not in scope: type constructor or class ‘Finalised’
File:     daml/Rental.daml
Hidden:   no
Range:    617:54-617:63
Source:   typecheck
Severity: DsError
Message:  daml/Rental.daml:617:55: error:Not in scope: type constructor or class ‘Finalised’
File:     daml/Rental.daml
Hidden:   no
Range:    618:16-629:38
Source:   typecheck
Severity: DsError
Message: 
  daml/Rental.daml:618:17: error:
  • Conflicting definitions for ‘agency’
  Bound at: daml/Rental.daml:(618,17)-(629,38)
  daml/Rental.daml:(618,17)-(629,38)
  • In a lambda abstraction
File:     daml/Rental.daml
Hidden:   no
Range:    619:27-619:36
Source:   typecheck
Severity: DsError
Message:  daml/Rental.daml:619:28: error:Not in scope: data constructor ‘Finalised’
File:     daml/Rental.daml
Hidden:   no
Range:    619:27-626:34
Source:   typecheck
Severity: DsError
Message:  daml/Rental.daml:619:28: error:duplicate field name ‘agency’ in record construction
ERROR: Creation of DAR file failed.

I went through every line, getting the indentation correct in the MaintenanceRequest template, I had it down to 1 single error, then tweaked something, and now this :joy: … I think this is an error of function, not format.

1 Like

Hi @quidagis, I can see 2 errors, one about Finalised not being found and one about a duplicate agency field. Could you commit and push your changes to a branch in your fork? This will make it easier to inspect them. Thanks!

2 Likes

Thank you for the feedback => Done.

1 Like

Thanks! Here are some initial suggestions to fix it:

  • A template parameter cannot be defined twice but you have two agency occurrences there; you can just remove one of them.
  • The choices available to the same controller should be under the same controller X can clause, i.e., you should not repeat the latter for the same controller.
  • All the contracts defined as result of choices (e.g. “Active”) should be defined as templates and I suggest to name them in such a way that they describe the process’ situation (e.g., “ActiveMaintenanceRequest”).
  • As for the process itself, I encourage you to first draw a diagram that shows how the process flows, i.e., how the maintenance is transitioned from one situation to the next one and who can do that. Then, a straightforward way to translate it in daml is to create one template per situation and one choice per arrow, with the controller being the party that can action the arrow.

For example, “Tenant contacts Agency about Maintenance issue” really means, in “situational” terms, “the tenant (of a specific rental) creates a new maintenance request that is then actionable by that rental’s agency”.

You have already many daml definition elements in the more detailed rephrasing above: a tenant party that is the tenant of a specific rental can create a new contract of MaintenanceRequest template, for that same rental only (so perhaps exercising a choice on that rental is the natural starting point?), where the rental’s agency is the controller of the next action (the confirmation, in this case). And so on.

Is it useful to think about it in this way?

Noted, thanks. That makes more sense than the variations using the base MaintenanceRequest template that I currently have :+1:t2:

Excellent advice. I noted that you had modelled it yourself previously, and since I prefer Words to Pictures, I just went straight to the list and tried to encode it using Daml ← fail :grimacing:

I think your suggestion is a good, longer term guide that I will incorporate into my work flow. I would assume that having such a large number of Templates, as matching the action items, give you a high degree of finite control on the overall process, and should reduce the scope for logic errors?

Given that MaintReq is one additional function that I can think of in Renting, the Rental.daml could expand considerably. In that case, how would you generally order the Templates? Alphabetically? Functionally and alphabetically? Or is it of no consequence to DAMLC?

I find it easy to think in terms of process states or, similarly, agreements/contracts (and you can think of templates as their “types” or “blueprints”, and the choices in them prescribe the possible actions or “options”) and there can be further mental models, I guess.

In the end, the current situation of a multi-party workflow is determined by the official (i.e., binding, as far as the parties are concerned) records that:

  1. describe the present state by providing information about it and its place in the process
  2. prescribe how it can be advanced, i.e. who can do what, when and at which conditions, potentially based on that information.

Note that templates, and the choices they define, play a role in both.

It’s really a matter of readability, understandability and how easily it can be evolved even without a lot of memory/knowledge/context about it. You could also split it into different modules.

2 Likes

It did not occur to do that, thanks, I will read further on this.

2 Likes

EDIT => Using Graphviz via a simple Dot file but tested using Viz.js

Logically it seems sound, but it just looks ‘off’ :thinking:

Maintenance_Request_Logic_Image

If anyone is interested, here is the code to make that image, using the Graphviz package installed via:

sudo apt install graphviz:

Maintenance_Request_Logic_Dot_Code
// Filename: daml_rental.dot
// Author: Quid Agis
// Version: 0.010
// Date: 03/05/2021


digraph Maintenance_Request {

        subgraph cluster_0 {
                style=filled;
                color=lightgrey;
                node [style=filled,color=white];
                Maint_Req_Open -> Agency_Confirms -> Repair_Less_300 -> Agency_Approves -> Provider_Contacts -> Repair_Actioned -> Tenant_Feedback -> If_Positive -> Agency_Inspects -> Agency_Closes -> Maint_Req_Closed;
                label = "Maintenance_Request";
        }

        subgraph cluster_1 {
                node [style=filled];
                Repair_Greater_300 -> Landlord_Approves ;
                label = "> $300, Approval";
                color=blue
        }

                subgraph cluster_2 {
                node [style=filled];
                Repair_Greater_300 -> Landlord_Refuses ;
                label = "> $300, Refusal";
                color=blue
        }

                subgraph cluster_3 {
                node [style=filled];
                Tenant_Feedback -> If_Negative -> Agency_Inspects -> Provider_Remediates -> Tenant_Feedback;
                label = "Repaired, Negative feedback";
                color=blue
        }

        Agency_Confirms -> Repair_Greater_300 ;
        Landlord_Approves -> Agency_Approves ;
        Landlord_Refuses -> Agency_Closes ;
}

Once the code is finalised, convert the code into an image:

# Convert
$ dot -Tpng -O daml_rental.dot
# View
$ xdg-open daml_rental.dot.png

Hi @quidagis, I am on Ubuntu 18.04 and can’t find graphiz; did you mean graphviz?

The graph nodes here seem to encode actions (with actors) rather than states (so choices rather than contracts, in daml parlance); I haven’t thought of that but I think this works too.

Did it help you with writing the process in daml? Looking forward to it!

2 Likes

Yes, Graphviz, thank you for seeing that. Errors corrected :+1:t2:

1 Like