Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

project-schema: Add Organization.beneficialOwners #427

Merged
merged 7 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,currency.csv -L tne,zar,fo,nam .
duncandewhurst marked this conversation as resolved.
Show resolved Hide resolved
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
2 changes: 2 additions & 0 deletions docs/reference/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
* `.transactions`
* `.milestones`
* `ContractingProcesses.milestones`
* [#427](https://github.com/open-contracting/infrastructure/pull/427) - add `Organization.beneficialOwners`

### Codelists

Expand All @@ -38,6 +39,7 @@
* milestoneType
* milestoneStatus
* milestoneCode
* [#427](https://github.com/open-contracting/infrastructure/pull/427) - add country codelist.
duncandewhurst marked this conversation as resolved.
Show resolved Hide resolved

### 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
45 changes: 33 additions & 12 deletions manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,21 +334,32 @@ 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[-1] == '0':
ref.pop(-1)
if ref[0] not in schema['definitions']:
duncandewhurst marked this conversation as resolved.
Show resolved Hide resolved
skip = False

definition["content"].extend([
"```{jsoninclude} ../../docs/examples/example.json\n",
f":jsonpointer: /projects/0/{'/'.join(ref)}\n",
f":title: {'/'.join(ref)}\n",
"```\n\n"
])
for path_to_skip in paths_to_skip:
if path_to_skip == '/'.join(ref)[:len(path_to_skip)]:
skip = True

if not skip:
if ref[-1] == '0':
ref.pop(-1)

definition["content"].extend([
"```{jsoninclude} ../../docs/examples/example.json\n",
f":jsonpointer: /projects/0/{'/'.join(ref)}\n",
f":title: {'/'.join(ref)}\n",
"```\n\n"
])

definition["content"].extend([
"````\n\n",
Expand Down Expand Up @@ -453,7 +464,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 +486,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 +512,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 +531,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 +763,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