docassemble
docassemble copied to clipboard
API call server-side with review
I am trying to run the following scenario: As part of an interview, I am collecting contract parties with name and address. Any contract party within our company, I have a central system which can deliver that information and is accessible via API. Hence, I would like to look-up name and address accordingly (each company has a unique ID that is used for lookup), but to it server-side (due to security reasons). But I need the user to review the information the system delivers as address and/or name may not always be entirely correct and may require user correction.
The below is my current code which works well, except for the fact that I did not find a way to present the derived information (company name and address) to the user for review. Ideally, the screen will show the question(s) relating to name and address with filled-in answers (like the review functionality) right after clicking the "Lookup" button (i. e. prior to clicking "continue").
Can someone help me find the "right" way?
objects:
- company: |
DAList.using(
object_type=Person,
there_are_any=True,
complete_attribute='complete')
---
code: |
company[i].name.text
company[i].address.address
company[i].address.zip
company[i].address.city
company[i].address.country
company[i].complete = True
---
question: |
What is the address of the
${ ordinal(i) } location?
subquestion: |
<span id="resultsArea"></span>
fields:
- Affiliate ID: companyID
datatype: integer
required: False
- html: |
<button id="run" class="btn btn-primary">Lookup</button>
- Company name: company[i].name.text
default: Company Ltd.
- Address: company[i].address.address
default: Some street 1
input type: area
rows: 2
- ZIP Code: company[i].address.zip
default: 12345
datatype: text
required: False
- City: company[i].address.city
default: Berlin
- Country: company[i].address.country
code: |
countries_list()
default: DE
script: |
<script>
$("#run").click(function(){
var s = getField('companyID').value;
console.log(s);
action_call('myaction', {affiliateID: s, i: ${i}}, function(data){
$("#resultsArea").html("The company name is " + data.result + ".")
});
});
</script>
---
event: myaction
code: |
affiliateID = action_argument('affiliateID')
i = action_argument('i')
# here comes a call to the API which gives a result
result = "The result is company with number " + affiliateID
company[i].complete = False
company[i].name.text = result
json_response(dict(result=result))
---
mandatory: True
question: |
The companies are...
subquestion: |
% for eachcompany in company:
* ${ eachcompany.name.text }
% endfor
---
question: |
Would you like to add another company?
yesno: company.there_is_another
Here is the simplest way to do it, without any asynchronous calls from the web browser:
objects:
- company: |
DAList.using(
object_type=Person,
there_are_any=True,
complete_attribute='complete')
---
code: |
company[i].lookup_attempted
company[i].name.text
company[i].address.address
company[i].address.zip
company[i].address.city
company[i].address.country
company[i].reviewed
company[i].complete = True
---
code: |
# Call your API here
if company[i].company_id == 42:
company[i].name.text = 'Foobar Gmbh'
company[i].address.address = '123 Main St.'
company[i].address.city = 'Hamburg'
company[i].address.country = 'DE'
company[i].address.zip = '23423'
company[i].lookup_attempted = True
---
question: |
What is the affiliate ID of the company?
subquestion: |
If you don't know it, just press Continue.
fields:
- Affiliate ID: company[i].company_id
datatype: integer
required: False
---
question: |
What is the address of the
${ ordinal(i) } location?
fields:
- Company name: company[i].name.text
default: Company Ltd.
- Address: company[i].address.address
default: Some street 1
input type: area
rows: 2
- ZIP Code: company[i].address.zip
default: 12345
datatype: text
required: False
- City: company[i].address.city
default: Berlin
- Country: company[i].address.country
code: |
countries_list()
default: DE
continue button field: company[i].reviewed
---
mandatory: True
question: |
The companies are...
subquestion: |
% for eachcompany in company:
* ${ eachcompany.name.text }
% endfor
---
question: |
Would you like to add another company?
yesno: company.there_is_another
Note that I used a continue button field to ensure that the user sees the screen with the address on it, regardless of whether or not the information was automatically filled in by the API call.
Here is a way to do it that is more similar to what you had written:
objects:
- company: |
DAList.using(
object_type=Person,
there_are_any=True,
complete_attribute='complete')
---
code: |
company[i].name.text
company[i].address.address
company[i].address.zip
company[i].address.city
company[i].address.country
company[i].reviewed
company[i].complete = True
---
question: |
What is the address of the
${ ordinal(i) } location?
subquestion: |
<span id="resultsArea"></span>
fields:
- Affiliate ID: company[i].company_id
datatype: integer
required: False
- html: |
<button id="run" class="btn btn-primary">Lookup</button>
- Company name: company[i].name.text
default: Company Ltd.
- Address: company[i].address.address
default: Some street 1
input type: area
rows: 2
- ZIP Code: company[i].address.zip
default: 12345
datatype: text
required: False
- City: company[i].address.city
default: Berlin
- Country: company[i].address.country
code: |
countries_list()
default: DE
continue button field: company[i].reviewed
script: |
<script>
$("#run").click(function(e){
var s = getField('company[i].company_id').value;
if (s){
console.log(s);
action_call('myaction', {affiliateID: s, i: ${i}}, function(data){
if (data.ok){
for (let [key, value] of Object.entries(data.result)) {
setField('company[i].' + key, value);
}
}
$("#resultsArea").html("Got response: " + data.message);
});
}
e.preventDefault();
return false;
});
</script>
---
event: myaction
code: |
indexno = int(action_argument('i'))
# here comes a call to the API which gives a result
company[indexno].company_id = int(action_argument('affiliateID'))
if company[indexno].company_id == 42:
json_response({'ok': True,
'message':
'Lookup successful',
'result': {
'name.text': 'Foobar Gmbh',
'address.address': '123 Main St.',
'address.city': 'Hamburg',
'address.country': 'DE',
'address.zip': '23423'
}
})
json_response({'ok': False, 'message': 'Could not find a company with that ID'})
---
mandatory: True
question: |
The companies are...
subquestion: |
% for eachcompany in company:
* ${ eachcompany.name.text }
% endfor
---
question: |
Would you like to add another company?
yesno: company.there_is_another
Note that it is very important to run .preventDefault() on a <button> event, otherwise the web browser will synchronously submit the <form>.
Here is a way to do it with action_perform().
objects:
- company: |
DAList.using(
object_type=Person,
there_are_any=True,
complete_attribute='complete')
---
code: |
company[i].name.text
company[i].address.address
company[i].address.zip
company[i].address.city
company[i].address.country
company[i].reviewed
company[i].complete = True
---
question: |
What is the address of the
${ ordinal(i) } location?
fields:
- Affiliate ID: company[i].company_id
datatype: integer
required: False
- html: |
<button id="run" class="btn btn-primary">Lookup</button>
- Company name: company[i].name.text
default: Company Ltd.
- Address: company[i].address.address
default: Some street 1
input type: area
rows: 2
- ZIP Code: company[i].address.zip
default: 12345
datatype: text
required: False
- City: company[i].address.city
default: Berlin
- Country: company[i].address.country
code: |
countries_list()
default: DE
continue button field: company[i].reviewed
script: |
<script>
$("#run").click(function(e){
var s = getField('company[i].company_id').value;
if (s){
console.log(s);
action_perform('myaction', {affiliateID: s, i: ${i}});
}
e.preventDefault();
return false;
});
</script>
---
event: myaction
code: |
indexno = int(action_argument('i'))
# here comes a call to the API which gives a result
company[indexno].company_id = int(action_argument('affiliateID'))
if company[indexno].company_id == 42:
company[indexno].name.text = 'Foobar Inc.'
company[indexno].address.address = '123 Main St'
company[indexno].address.city = 'Hamburg'
company[indexno].address.zip = '02020'
company[indexno].address.country = 'DE'
log('Lookup successful', 'success')
else:
log('Could not find a company with that ID', 'info')
---
mandatory: True
question: |
The companies are...
subquestion: |
% for eachcompany in company:
* ${ eachcompany.name.text }
% endfor
---
question: |
Would you like to add another company?
yesno: company.there_is_another
I don't think there is any one "right" way to do this.
As always, 1000 thanks. This are 3 perfect solutions to my issue...