Skip to content

Commit

Permalink
Merge pull request #427 from open-contracting/399-beneficial-owners
Browse files Browse the repository at this point in the history
project-schema: Add Organization.beneficialOwners
  • Loading branch information
duncandewhurst authored Nov 14, 2023
2 parents 97ec8a4 + 8e0209c commit 51e9c4f
Show file tree
Hide file tree
Showing 12 changed files with 777 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/spellcheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ jobs:
with:
python-version: '3.10'
- run: pip install codespell
- run: codespell -S .git,docson,locale,currency.csv -L tne,zar .
- run: codespell -S .git,docson,locale,country.csv,currency.csv -L fo,tne,zar .
41 changes: 40 additions & 1 deletion docs/_static/i18n.csv
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,49 @@ parties/contactPoint/telephone,Telephone,True,
parties/contactPoint/faxNumber,Fax number,True,
parties/contactPoint/url,URL,False,
parties/roles,Party roles,False,
parties/beneficialOwners,Beneficial owners,False,
parties/beneficialOwners,Person,False,
parties/beneficialOwners/id,ID,True,
parties/beneficialOwners/name,Name,True,
parties/beneficialOwners/identifier,Identifier,False,
parties/beneficialOwners/identifier,Identifier,False,
parties/beneficialOwners/identifier/scheme,Scheme,True,
parties/beneficialOwners/identifier/id,ID,True,
parties/beneficialOwners/identifier/legalName,Legal Name,True,
parties/beneficialOwners/identifier/uri,URI,False,
parties/beneficialOwners/nationalities,Nationalities,False,
parties/beneficialOwners/address,Address,False,
parties/beneficialOwners/address,Address,False,
parties/beneficialOwners/address/streetAddress,Street address,True,
parties/beneficialOwners/address/locality,Locality,True,
parties/beneficialOwners/address/region,Region,True,
parties/beneficialOwners/address/postalCode,Postal code,True,
parties/beneficialOwners/address/countryName,Country name,True,
parties/beneficialOwners/email,Email,False,
parties/beneficialOwners/faxNumber,Fax number,True,
parties/beneficialOwners/telephone,Telephone,True,
parties/beneficialOwners/jobTitle,Job title,True,
parties/people,People,False,
parties/people,Person,False,
parties/people/id,Identifier,True,
parties/people/id,ID,True,
parties/people/name,Name,True,
parties/people/identifier,Identifier,False,
parties/people/identifier,Identifier,False,
parties/people/identifier/scheme,Scheme,True,
parties/people/identifier/id,ID,True,
parties/people/identifier/legalName,Legal Name,True,
parties/people/identifier/uri,URI,False,
parties/people/nationalities,Nationalities,False,
parties/people/address,Address,False,
parties/people/address,Address,False,
parties/people/address/streetAddress,Street address,True,
parties/people/address/locality,Locality,True,
parties/people/address/region,Region,True,
parties/people/address/postalCode,Postal code,True,
parties/people/address/countryName,Country name,True,
parties/people/email,Email,False,
parties/people/faxNumber,Fax number,True,
parties/people/telephone,Telephone,True,
parties/people/jobTitle,Job title,True,
publicAuthority,Public authority,False,
publicAuthority,Organization reference,False,
Expand Down
82 changes: 56 additions & 26 deletions docs/cost/ids/sustainability.md
Original file line number Diff line number Diff line change
Expand Up @@ -1466,38 +1466,45 @@ OC4IDS mapping
^^^
For each planned disbursement:
* If the disbursement relates to a contracting processes, for example a payment from a funder to a supplier or subcontractor of a supplier, get the `ContractingProcess` in the `.contractingProcesses` array to which the disbursement relates and add a `Milestone` object to its `.summary.milestones` array. Otherwise, if the disbursement relates to the project, for example a payment from a funder to the public authority, add a `Milestone` object to the project-level `.milestones` array.
* Set the milestone's:
* `.id` incrementally
* `.status` to 'scheduled'
* `.dueDate` to the date on which the disbursement is planned to occur
* `.type` to 'payment'
* `.value` to the amount and currency of the planned disbursement
- If the disbursement relates to a contracting processes, for example a payment from a funder to a supplier or subcontractor of a supplier, get the `ContractingProcess` in the `.contractingProcesses` array to which the disbursement relates and add a `Milestone` object to its `.summary.milestones` array. Otherwise, if the disbursement relates to the project, for example a payment from a funder to the public authority, add a `Milestone` object to the project-level `.milestones` array.
- Set the milestone's:
- `.id` incrementally
- `.status` to 'scheduled'
- `.dueDate` to the date on which the disbursement is planned to occur
- `.type` to 'payment'
- `.value` to the amount and currency of the planned disbursement
For each actual disbursement:
* If the disbursement relates to a contracting processes, for example a payment from a funder to a supplier or subcontractor of a supplier, get the `ContractingProcess` in the `.contractingProcesses` array to which the disbursement relates and add a `Transaction` object to its `.summary.transactions` array. Otherwise, if the disbursement relates to the project, for example a payment from a funder to the public authority, add a `Transaction` object to the project-level `.transactions` array.
* Set the transaction's:
* `.id` incrementally
* `.date` to the date of the disbursement
* `.value` to the amount and currency of the disbursement
* Get the `Organization` in `.parties` that represents the payer. If none exists yet, [add an organization](../common.md#add-an-organization) for the payer:
* Add 'payer' to the organization's `.roles` array
* Set the transaction's `.payer` to the `.id` and `.name` of the organization
* Get the `Organization` in `.parties` that represents the payee. If none exists yet, [add an organization](../common.md#add-an-organization) for the payee:
* Add 'payee' to the organization's `.roles` array.
* Set the transaction's `.payee` to the `.id` and `.name` of the organization
* Get the `Milestone` in `.milestones` that represents that planned disbursement:
* Set its `.status` to 'met'
* Set its `.dateMet` to the date of the disbursement
* Set the transaction's `.relatedImplementationMilestone` to the `.id` and `.title` of the milestone
- If the disbursement relates to a contracting processes, for example a payment from a funder to a supplier or subcontractor of a supplier, get the `ContractingProcess` in the `.contractingProcesses` array to which the disbursement relates and add a `Transaction` object to its `.summary.transactions` array. Otherwise, if the disbursement relates to the project, for example a payment from a funder to the public authority, add a `Transaction` object to the project-level `.transactions` array.
- Set the transaction's:
- `.id` incrementally
- `.date` to the date of the disbursement
- `.value` to the amount and currency of the disbursement
- Get the `Organization` in `.parties` that represents the payer. If none exists yet, [add an organization](../common.md#add-an-organization) for the payer:
- Add 'payer' to the organization's `.roles` array
- Set the transaction's `.payer` to the `.id` and `.name` of the organization
- Get the `Organization` in `.parties` that represents the payee. If none exists yet, [add an organization](../common.md#add-an-organization) for the payee:
- Add 'payee' to the organization's `.roles` array.
- Set the transaction's `.payee` to the `.id` and `.name` of the organization
- Get the `Milestone` in `.milestones` that represents that planned disbursement:
- Set its `.status` to 'met'
- Set its `.dateMet` to the date of the disbursement
- Set the transaction's `.relatedImplementationMilestone` to the `.id` and `.title` of the milestone
```json
{
"milestones": [
{
"id": "1",
"title": "Grant disbursement"
"title": "Grant disbursement",
"status": "met",
"dueDate": "2023-07-01T00:00:00Z",
"dateMet": "2023-08-01T00:00:00Z",
Expand Down Expand Up @@ -2876,9 +2883,32 @@ Disclose the beneficial owners of the contractors and suppliers appointed in the
:columns: 8
OC4IDS mapping
^^^
Use modelling from OCDS Beneficial Owners extension
```json
For each beneficial owner:
- Get the `Organization` in `.parties` that represents the contractor or supplier.
- Add a `Person` object to the organization's `.beneficialOwners` array.
- Set the person's:
- `.id` incrementally
- `.name` to the beneficial owner's name
- `.identifier` to the beneficial owner's identifier
```json
{
"parties": [
{
"id": "1",
"beneficialOwners": [
{
"id": "1",
"name": "Juan Perez",
"identifier": {
"scheme": "PRY-IDCARD",
"id": "12345"
}
}
]
}
]
}
```
````
Expand Down
23 changes: 23 additions & 0 deletions docs/examples/blank.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,29 @@
"name": "",
"jobTitle": ""
}
],
"beneficialOwners": [
{
"id": "string",
"name": "string",
"identifier": {
"scheme": "string",
"id": "string"
},
"nationalities": [
"string"
],
"address": {
"streetAddress": "string",
"locality": "string",
"region": "string",
"postalCode": "string",
"countryName": "string"
},
"email": "string",
"faxNumber": "string",
"telephone": "string"
}
]
}
],
Expand Down
23 changes: 23 additions & 0 deletions docs/examples/example.json
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,29 @@
"roles": [
"supplier",
"tenderer"
],
"beneficialOwners": [
{
"id": "1",
"name": "Juan Perez",
"identifier": {
"scheme": "PRY-IDCARD",
"id": "12345"
},
"nationalities": [
"PY"
],
"address": {
"streetAddress": "Avenida Eusebio Ayala 1347",
"locality": "Asunción",
"region": "Gran Asunción",
"postalCode": "1001",
"countryName": "Paraguay"
},
"email": "[email protected]",
"faxNumber": "+595210000001",
"telephone": "+595210000000"
}
]
},
{
Expand Down
12 changes: 7 additions & 5 deletions docs/reference/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,18 @@
* `.transactions`
* `.milestones`
* `ContractingProcesses.milestones`
* [#427](https://github.com/open-contracting/infrastructure/pull/427) - add `Organization.beneficialOwners`

### Codelists

* [#355](https://github.com/open-contracting/infrastructure/pull/355) - use correct normative and non-normative keywords codelist descriptions.
* [#369](https://github.com/open-contracting/infrastructure/pull/369) - add classification scheme codelist.
* [#377](https://github.com/open-contracting/infrastructure/pull/377) - clarify business logic in contractingProcessStatus codelist.
* [#426](https://github.com/open-contracting/infrastructure/pull/426) - add codelists:
* milestoneType
* milestoneStatus
* milestoneCode
* add codelists:
* [#369](https://github.com/open-contracting/infrastructure/pull/369) - classificationScheme
* [#427](https://github.com/open-contracting/infrastructure/pull/427) - country
* [#426](https://github.com/open-contracting/infrastructure/pull/426) - milestoneType
* [#426](https://github.com/open-contracting/infrastructure/pull/426) - milestoneStatus
* [#426](https://github.com/open-contracting/infrastructure/pull/426) - milestoneCode

### Other

Expand Down
7 changes: 7 additions & 0 deletions docs/reference/codelists.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ Projects with a `status` of 'completed' may be displayed in a list of archived p
:file: ../../build/current_lang/codelists/milestoneType.csv
```

### country

```{csv-table-no-translate}
:header-rows: 1
:file: ../../build/current_lang/codelists/country.csv
```

## Open codelists

### DocumentType
Expand Down
7 changes: 5 additions & 2 deletions docs/reference/schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ Each `Organization` has the following fields:
```{jsonschema} ../../build/current_lang/project-schema.json
:pointer: /definitions/Organization
:collapse: name,id,identifier,additionalIdentifiers,address,contactPoint,roles,people
:collapse: name,id,identifier,additionalIdentifiers,address,contactPoint,roles,beneficialOwners,people
:addtargets:
```
Expand Down Expand Up @@ -574,6 +574,7 @@ When working with data, users ought to be aware that addresses might not always
This sub-schema is referenced by the following properties:
* [`Location/address`](project-schema.json,/definitions/Location,address)
* [`Organization/address`](project-schema.json,/definitions/Organization,address)
* [`Person/address`](project-schema.json,/definitions/Person,address)

Each `Address` has the following fields:

Expand Down Expand Up @@ -734,6 +735,7 @@ For example, if identifying a company in Colombia, look up its identifier in the
This sub-schema is referenced by the following properties:
* [`Organization/identifier`](project-schema.json,/definitions/Organization,identifier)
* [`Organization/additionalIdentifiers`](project-schema.json,/definitions/Organization,additionalIdentifiers)
* [`Person/identifier`](project-schema.json,/definitions/Person,identifier)

Each `Identifier` has the following fields:

Expand Down Expand Up @@ -891,6 +893,7 @@ Use this object when you need to disclose the details of people associated with,
```

This sub-schema is referenced by the following properties:
* [`Organization/beneficialOwners`](project-schema.json,/definitions/Organization,beneficialOwners)
* [`Organization/people`](project-schema.json,/definitions/Organization,people)

Each `Person` has the following fields:
Expand All @@ -901,7 +904,7 @@ Each `Person` has the following fields:
```{jsonschema} ../../build/current_lang/project-schema.json
:pointer: /definitions/Person
:collapse: id,name,jobTitle
:collapse: id,name,identifier,nationalities,address,email,faxNumber,telephone,jobTitle
:addtargets:
```
Expand Down
22 changes: 18 additions & 4 deletions manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,16 @@ def update_sub_schema_reference(schema):
])

# Paths that don't appear in the example data at all
paths_to_skip = ['forecasts/0/observations/0/value', 'metrics/0/observations/0/value']
paths_to_skip = ['forecasts/0/observations/0/value',
'metrics/0/observations/0/value',
'parties/0/beneficialOwners/0',
'parties/0/people/0/address',
'parties/0/people/0/identifier']

# Add examples
definition["references"] = get_definition_references(schema, defn)
for ref in definition["references"]:
if ref[0] not in schema['definitions'] and '/'.join(ref) not in paths_to_skip:
if ref[0] not in schema['definitions'] and not any(p == '/'.join(ref)[:len(p)] for p in paths_to_skip):
if ref[-1] == '0':
ref.pop(-1)

Expand Down Expand Up @@ -453,7 +457,8 @@ def copy_element(name, replacements=None, root='definitions'):

ocds_base_url = 'https://standard.open-contracting.org/1.1/en/'

builder = ProfileBuilder('1__1__5', {'budget': 'master', 'transaction_milestones': 'master'})
builder = ProfileBuilder('1__1__5',
{'budget': 'master', 'transaction_milestones': 'master', 'beneficialOwners': 'master'})
ppp_schema = get(f'{ppp_base_url}release-schema.json').json()
ppp_schema = builder.patched_release_schema(schema=ppp_schema)

Expand All @@ -474,6 +479,7 @@ def copy_element(name, replacements=None, root='definitions'):
'relatedProjectScheme.csv',
'relatedProject.csv',
'classificationScheme.csv',
'country.csv',
}
ocds_codelists = {
'currency.csv',
Expand All @@ -499,7 +505,6 @@ def copy_element(name, replacements=None, root='definitions'):
'LinkedRelease', # Similar to linked release in OCDS
'Modification',
'RelatedProject', # Similar to relatedProcess in OCDS
'Person',
'SimpleIdentifier',
}
ocds_definitions = {
Expand All @@ -519,6 +524,7 @@ def copy_element(name, replacements=None, root='definitions'):
'Transaction',
'Milestone',
'MilestoneReference',
'Person',
}
compare(schema['definitions'], infra_definitions, ocds_definitions,
'schema/project-level/project-schema.json#/definitions', 'definitions')
Expand Down Expand Up @@ -750,6 +756,14 @@ def copy_element(name, replacements=None, root='definitions'):
# Original from standard: "The title of the milestone being referenced, this must match the title of a milestone described elsewhere in a release about this contracting process." # noqa: E501
schema['definitions']['MilestoneReference']['properties']['title']['description'] = "The title of the milestone being referenced, this must match the title of a milestone in this project or contracting process's `.milestones`." # noqa: E501

copy_element('Person')
schema['definitions']['Person']['properties']['jobTitle'] = {
"title": "Job title",
"description": "The job title of the person (for example, Financial Manager).",
"type": "string",
"minLength": 1
}

remove_null_and_pattern_properties(schema)
remove_integer_identifier_types(schema)
remove_deprecated_properties(schema)
Expand Down
Loading

0 comments on commit 51e9c4f

Please sign in to comment.