From f19cb020c3c19c40d100190beabac17f626c3397 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 13:43:42 +1300 Subject: [PATCH 01/13] schema/project-level/project-schema.json: Add and update fields Add project-level transactions. Add milestones to projects and contracting processes. Add milestoneType and milestoneStatus codelists. Update schema for latest version of OCDS for PPPs --- manage.py | 35 +++- .../codelists/milestoneStatus.csv | 5 + .../project-level/codelists/milestoneType.csv | 11 ++ schema/project-level/project-schema.json | 176 +++++++++++++++--- 4 files changed, 199 insertions(+), 28 deletions(-) create mode 100644 schema/project-level/codelists/milestoneStatus.csv create mode 100644 schema/project-level/codelists/milestoneType.csv diff --git a/manage.py b/manage.py index 23ea5f66..01117bb7 100755 --- a/manage.py +++ b/manage.py @@ -4,7 +4,7 @@ import re import sys import warnings -from collections import defaultdict +from collections import defaultdict, OrderedDict from copy import deepcopy from io import StringIO from pathlib import Path @@ -473,6 +473,7 @@ def copy_element(name, replacements=None, root='definitions'): 'projectType.csv', 'relatedProjectScheme.csv', 'relatedProject.csv', + 'classificationScheme.csv', } ocds_codelists = { 'currency.csv', @@ -485,6 +486,8 @@ def copy_element(name, replacements=None, root='definitions'): 'partyRole.csv', 'releaseTag.csv', 'unitClassificationScheme.csv', + 'milestoneType.csv', + 'milestoneStatus.csv', } compare([path.name for path in codelists_dir.iterdir()], infra_codelists, ocds_codelists, 'schema/project-level/codelists', 'codelists') @@ -496,6 +499,7 @@ def copy_element(name, replacements=None, root='definitions'): 'Modification', 'RelatedProject', # Similar to relatedProcess in OCDS 'Person', + 'SimpleIdentifier', } ocds_definitions = { 'Period', @@ -512,6 +516,7 @@ def copy_element(name, replacements=None, root='definitions'): 'Metric', 'Observation', 'Transaction', + 'Milestone' } compare(schema['definitions'], infra_definitions, ocds_definitions, 'schema/project-level/project-schema.json#/definitions', 'definitions') @@ -630,12 +635,11 @@ def copy_element(name, replacements=None, root='definitions'): }) copy_element('Classification', { - # Remove line item classifications from the definition. - ('properties', 'scheme', 'description'): lambda s: s[:s.index(' For line item classifications,')], + # Replace line item classification scheme codelist with classification scheme codelist + ('properties', 'scheme', 'description'): lambda s: s.replace('. For line item classifications, this uses the open [itemClassificationScheme](https://standard.open-contracting.org/1.1/en/schema/codelists/#item-classification-scheme) codelist.', ', using the open [classificationScheme](https://standard.open-contracting.org/infrastructure/{{version}}/{{lang}}/reference/codelists/#classificationscheme) codelist.'), # noqa: E501 }) - # Remove the `itemClassificationScheme.csv` codelist. - del schema['definitions']['Classification']['properties']['scheme']['codelist'] - del schema['definitions']['Classification']['properties']['scheme']['openCodelist'] + # Replace line item classification scheme codelist with classification scheme codelist + schema['definitions']['Classification']['properties']['scheme']['codelist'] = 'classificationScheme.csv' copy_element('Location') # Original from ocds_location_extension: "The location where activity related to this tender, contract or license will be delivered, or will take place. A location can be described by either a geometry (point location, line or polygon), or a gazetteer entry, or both." # noqa: E501 @@ -653,6 +657,7 @@ def copy_element(name, replacements=None, root='definitions'): 'description': 'A physical address where works will take place.', '$ref': '#/definitions/Address', } + schema['definitions']['Location']['properties'] = OrderedDict(schema['definitions']['Location']['properties']) schema['definitions']['Location']['properties'].move_to_end('id', last=False) schema['definitions']['Location']['required'] = ['id'] @@ -693,7 +698,13 @@ def copy_element(name, replacements=None, root='definitions'): ('properties', 'name', 'description'): lambda s: s.replace('contracting process', 'project'), }) - copy_element('BudgetBreakdown') + copy_element('BudgetBreakdown', { + # Refer to project instead of contracting process + ('properties', 'amount', 'description'): lambda s: s.replace('contracting process', 'project',) + }) + # Add approval date + schema['definitions']['BudgetBreakdown']['properties']['approvalDate'] = deepcopy(schema['properties']['budget']['properties']['approvalDate']) # noqa: E501 + schema['definitions']['BudgetBreakdown']['properties']['approvalDate']['description'] = "The date on which this budget entry was approved. Where documentary evidence for this exists, it may be included among the project documents with `.documentType` set to 'budgetApproval'." # noqa: E501 copy_element('Document', { # Link to infrastructure codelist instead of PPP codelist @@ -717,6 +728,16 @@ def copy_element(name, replacements=None, root='definitions'): del schema['definitions']['Observation']['properties']['relatedImplementationMilestone'] copy_element('Transaction') + # Original from standard: "A spending transaction related to the contracting process. Draws upon the data models of the [Fiscal Data Package](https://frictionlessdata.io/specs/fiscal-data-package/) and the [International Aid Transparency Initiative](http://iatistandard.org/activity-standard/iati-activities/iati-activity/transaction/) and should be used to cross-reference to more detailed information held using a Fiscal Data Package, IATI file, or to provide enough information to allow a user to manually or automatically cross-reference with some other published source of transactional spending data." # noqa: E501 + schema['definitions']['Transaction']['description'] = "A financial transaction related to a project or contracting process. Draws upon the data models of the Fiscal Data Package and the International Aid Transparency Initiative and should be used to cross-reference to more detailed information held using a Fiscal Data Package, IATI file, or to provide enough information to allow a user to manually or automatically cross-reference with some other published source of transactional data." # noqa: E501 + + copy_element('Milestone') + # Original from standard: "The milestone block can be used to represent a wide variety of events in the lifetime of a contracting process." # noqa: E501 + schema['definitions']['Milestone']['description'] = "An event in the lifetime of a project or contracting process." # noqa: E501 + # Original from standard: "A local identifier for this milestone, unique within this block. This field is used to keep track of multiple revisions of a milestone through the compilation from release to record mechanism." # noqa: E501 + schema['definitions']['Milestone']['properties']['id']['description'] = "A local identifier for this milestone, unique within this block." # noqa: E501 + # Original from standard: "Milestone codes can be used to track specific events that take place for a particular kind of contracting process. For example, a code of 'approvalLetter' can be used to allow applications to understand this milestone represents the date an approvalLetter is due or signed." # noqa: E501 + schema['definitions']['Milestone']['properties']['code']['description'] = "Milestone codes can be used to track specific events that take place for a particular kind of project or contracting process. For example, a code of 'approvalLetter' can be used to allow applications to understand this milestone represents the date an approvalLetter is due or signed." # noqa: E501 remove_null_and_pattern_properties(schema) remove_integer_identifier_types(schema) diff --git a/schema/project-level/codelists/milestoneStatus.csv b/schema/project-level/codelists/milestoneStatus.csv new file mode 100644 index 00000000..ea288709 --- /dev/null +++ b/schema/project-level/codelists/milestoneStatus.csv @@ -0,0 +1,5 @@ +Code,Title,Description,Extension +scheduled,Scheduled,This milestone has been scheduled for the date in milestone.dueDate. Progress towards the milestone has not yet been evaluated as of milestone.dateModified.,OCDS Core +met,Met,This milestone has been achieved. The date on which it was met should be placed in the milestone.dateMet field.,OCDS Core +notMet,Not met,This milestone had not been met at the date it was last reviewed (see milestone.dateModified).,OCDS Core +partiallyMet,Partially met,This milestone was judged to have been partially met at the date it was last reviewed (see milestone.dateModified).,OCDS Core diff --git a/schema/project-level/codelists/milestoneType.csv b/schema/project-level/codelists/milestoneType.csv new file mode 100644 index 00000000..06e077b0 --- /dev/null +++ b/schema/project-level/codelists/milestoneType.csv @@ -0,0 +1,11 @@ +Code,Title,Description,Extension +preProcurement,Pre-procurement milestones,"For events during the planning or pre-procurement phase of a process, such as the preparation of key studies.",OCDS Core +approval,Approval milestones,For events such as the sign-off of a contract or project.,OCDS Core +engagement,Engagement milestones,"For engagement milestones, such as a public hearing.",OCDS Core +assessment,Assessment milestones,"For assessment and adjudication milestones, such as the meeting date of a committee.",OCDS Core +delivery,Delivery milestones,"For delivery milestones, such as the date when a good or service is to be provided.",OCDS Core +reporting,Reporting milestones,"For reporting milestones, such as when key reports are to be provided.",OCDS Core +financing,Financing milestones,"For events related to the funding of the project or contracting process. In public-private partnerships, such events might include, for example, planned payments and equity transfers.",OCDS Core +payment,Payment milestones,"For payment milestones, such as the date when a payment is expected to be made to a supplier. If the `status` of a project or contracting process's payment milestone is 'met', then the contract ought to have an entry for the payment under its `.transactions`.",OCDS Core +procurement,Procurement,"Events taking place during the procurement which are not captured by fields in core OCDS, such as additional enquiry periods or draft tender submissions in a competitive dialogue process",OCDS for PPPs Extension +contractClose,Contract close,Events such as commercial and financial close,OCDS for PPPs Extension diff --git a/schema/project-level/project-schema.json b/schema/project-level/project-schema.json index dbad6ad6..62ad4a7e 100644 --- a/schema/project-level/project-schema.json +++ b/schema/project-level/project-schema.json @@ -225,6 +225,26 @@ "uniqueItems": true, "minItems": 1 }, + "transactions": { + "title": "Transactions", + "description": "Financial transactions related to this project. For example, a disbursement from a funder to the project company. Transactions related to a contracting process, like a disbursement from a funder to a supplier, should be recorded in the contracting process summary's `.transactions.`", + "type": "array", + "items": { + "$ref": "#/definitions/Transaction" + }, + "minItems": 1, + "uniqueItems": true + }, + "milestones": { + "title": "Milestones", + "description": "Milestones associated with this project.", + "type": "array", + "items": { + "$ref": "#/definitions/Milestone" + }, + "minItems": 1, + "uniqueItems": true + }, "completion": { "title": "Completion", "description": "This information is provided at project completion, and reflects the final timing and values relating to the project. The reason for any variation (not already explained) between the anticipated project scope, period and value should be detailed.", @@ -270,7 +290,7 @@ }, "language": { "title": "Language", - "description": "The default language of the data using either two-letter [ISO639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes), or extended [BCP47 language tags](https://www.w3.org/International/articles/language-tags/). The use of lowercase two-letter codes from [ISO639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) is recommended.", + "description": "The default language of the data using either two-letter [ISO639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes), or extended [BCP47 language tags](http://www.w3.org/International/articles/language-tags/). The use of lowercase two-letter codes from [ISO639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) is recommended.", "type": [ "string" ], @@ -490,6 +510,16 @@ }, "uniqueItems": true, "minItems": 1 + }, + "milestones": { + "title": "Milestones", + "description": "Milestones associated with this contracting process.", + "type": "array", + "items": { + "$ref": "#/definitions/Milestone" + }, + "minItems": 1, + "uniqueItems": true } }, "minProperties": 1 @@ -682,7 +712,9 @@ "scheme": { "title": "Scheme", "description": "The scheme or codelist from which the classification code is taken, using the open [classificationScheme](https://standard.open-contracting.org/infrastructure/{{version}}/{{lang}}/reference/codelists/#classificationscheme) codelist.", - "type": "string", + "type": [ + "string" + ], "codelist": "classificationScheme.csv", "openCodelist": true, "minLength": 1 @@ -735,11 +767,11 @@ "geometry": { "type": "object", "title": "Geometry", - "description": "We follow the [GeoJSON standard](https://geojson.org/) to express basic location information, using longitude, latitude, and optional elevation values in the [WGS84](https://en.wikipedia.org/wiki/World_Geodetic_System) (EPSG:4326) projection. A point location can be identified by geocoding a delivery address. For concession licenses, or other contracts covering a polygon location which is not contained in a known gazetteer, polygon and multi-polygon can be used.", + "description": "We follow the [GeoJSON standard](http://geojson.org/) to express basic location information, using longitude, latitude, and optional elevation values in the [WGS84](https://en.wikipedia.org/wiki/World_Geodetic_System) (EPSG:4326) projection. A point location can be identified by geocoding a delivery address. For concession licenses, or other contracts covering a polygon location which is not contained in a known gazetteer, polygon and multi-polygon can be used.", "properties": { "type": { "title": "Type", - "description": "The type of [GeoJSON Geometry Objects](https://geojson.org/geojson-spec.html#geometry-objects) being provided. To provide longitude, latitude, and optional elevation, use 'Point', and enter an array of [longitude, latitude] or [longitude, latitude, elevation] as the value of the coordinates field: e.g. [-122.085, 37.42].", + "description": "The type of [GeoJSON Geometry Objects](http://geojson.org/geojson-spec.html#geometry-objects) being provided. To provide longitude, latitude, and optional elevation, use 'Point', and enter an array of [longitude, latitude] or [longitude, latitude, elevation] as the value of the coordinates field: e.g. [-122.085, 37.42].", "type": [ "string" ], @@ -1344,9 +1376,9 @@ "minProperties": 1 }, "BudgetBreakdown": { - "type": "object", "title": "Detailed budget breakdown", "description": "This section allows a detailed budget breakdown to be expressed, covering multiple budget sources and multiple periods", + "type": "object", "required": [ "id" ], @@ -1367,15 +1399,9 @@ }, "amount": { "title": "Amount", - "description": "The value of the budget line item.", + "description": "The value of the budget line item. A positive amount means the source organization funds the project. A negative amount means the project pays the source organization.", "$ref": "#/definitions/Value" }, - "approvalDate": { - "title": "Approval date", - "description": "The date on which this budget entry was approved. Where documentary evidence for this exists, it may be included among the project documents with `.documentType` set to 'budgetApproval'.", - "type": "string", - "format": "date-time" - }, "uri": { "title": "Linked budget information", "description": "A URI pointing directly to a machine-readable information about this budget entry.", @@ -1385,14 +1411,20 @@ "format": "uri" }, "period": { - "$ref": "#/definitions/Period", "title": "Budget period", - "description": "The period covered by this budget entry." + "description": "The period covered by this budget entry.", + "$ref": "#/definitions/Period" }, "sourceParty": { - "$ref": "#/definitions/OrganizationReference", - "title": "Source party", - "description": "An organization reference, linking to the entry in the `parties` section describing the organization providing the funds for this part of the budget. The party must have the 'funder' role. If the budget amount is positive, this indicates a flow of resources from the party to the contracting process. If the budget amount is negative, it indicates a payment from the contracting process to this party." + "title": "Source organization", + "description": "The organization providing the funds for this budget entry. The corresponding entry in the `parties` array must have 'sourceParty' in its `roles` array.", + "$ref": "#/definitions/OrganizationReference" + }, + "approvalDate": { + "title": "Approval date", + "description": "The date on which this budget entry was approved. Where documentary evidence for this exists, it may be included among the project documents with `.documentType` set to 'budgetApproval'.", + "type": "string", + "format": "date-time" } }, "minProperties": 1 @@ -1463,7 +1495,7 @@ }, "format": { "title": "Format", - "description": "The format of the document, using the open [IANA Media Types](https://www.iana.org/assignments/media-types/) codelist (see the values in the 'Template' column), or using the 'offline/print' code if the described document is published offline. For example, web pages have a format of 'text/html'.", + "description": "The format of the document, using the open [IANA Media Types](http://www.iana.org/assignments/media-types/) codelist (see the values in the 'Template' column), or using the 'offline/print' code if the described document is published offline. For example, web pages have a format of 'text/html'.", "type": [ "string" ], @@ -1471,7 +1503,7 @@ }, "language": { "title": "Language", - "description": "The language of the linked document using either two-letter [ISO639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes), or extended [BCP47 language tags](https://www.w3.org/International/articles/language-tags/). The use of lowercase two-letter codes from [ISO639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) is recommended unless there is a clear user need for distinguishing the language subtype.", + "description": "The language of the linked document using either two-letter [ISO639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes), or extended [BCP47 language tags](http://www.w3.org/International/articles/language-tags/). The use of lowercase two-letter codes from [ISO639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) is recommended unless there is a clear user need for distinguishing the language subtype.", "type": [ "string" ], @@ -1542,7 +1574,7 @@ }, "uri": { "title": "URI", - "description": "A URI to identify the organization, such as those provided by [Open Corporates](https://opencorporates.com) or some other relevant URI provider. This is not for listing the website of the organization: that can be done through the URL field of the Organization contact point.", + "description": "A URI to identify the organization, such as those provided by [Open Corporates](http://www.opencorporates.com) or some other relevant URI provider. This is not for listing the website of the organization: that can be done through the URL field of the Organization contact point.", "type": [ "string" ], @@ -1769,7 +1801,7 @@ "Transaction": { "type": "object", "title": "Transaction information", - "description": "A spending transaction related to the contracting process. Draws upon the data models of the [Fiscal Data Package](https://frictionlessdata.io/specs/fiscal-data-package/) and the [International Aid Transparency Initiative](https://iatistandard.org/activity-standard/iati-activities/iati-activity/transaction/) and should be used to cross-reference to more detailed information held using a Fiscal Data Package, IATI file, or to provide enough information to allow a user to manually or automatically cross-reference with some other published source of transactional spending data.", + "description": "A financial transaction related to a project or contracting process. Draws upon the data models of the Fiscal Data Package and the International Aid Transparency Initiative and should be used to cross-reference to more detailed information held using a Fiscal Data Package, IATI file, or to provide enough information to allow a user to manually or automatically cross-reference with some other published source of transactional data.", "required": [ "id" ], @@ -1844,6 +1876,108 @@ "id" ], "minProperties": 1 + }, + "Milestone": { + "title": "Milestone", + "description": "An event in the lifetime of a project or contracting process.", + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "title": "ID", + "description": "A local identifier for this milestone, unique within this block.", + "type": "string", + "minLength": 1 + }, + "title": { + "title": "Title", + "description": "Milestone title", + "type": [ + "string" + ], + "minLength": 1 + }, + "type": { + "title": "Milestone type", + "description": "The nature of the milestone, using the open [milestoneType](https://standard.open-contracting.org/profiles/ppp/latest/en/reference/codelists/#milestonetype) codelist.", + "type": [ + "string" + ], + "codelist": "milestoneType.csv", + "openCodelist": true, + "minLength": 1 + }, + "description": { + "title": "Description", + "description": "A description of the milestone.", + "type": [ + "string" + ], + "minLength": 1 + }, + "code": { + "title": "Milestone code", + "description": "Milestone codes can be used to track specific events that take place for a particular kind of project or contracting process. For example, a code of 'approvalLetter' can be used to allow applications to understand this milestone represents the date an approvalLetter is due or signed.", + "type": [ + "string" + ], + "codelist": "milestoneCode.csv", + "openCodelist": true, + "minLength": 1 + }, + "dueDate": { + "title": "Due date", + "description": "The date the milestone is due.", + "type": [ + "string" + ], + "format": "date-time" + }, + "dateMet": { + "format": "date-time", + "title": "Date met", + "description": "The date on which the milestone was met.", + "type": [ + "string" + ] + }, + "dateModified": { + "title": "Date modified", + "description": "The date the milestone was last reviewed or modified and the status was altered or confirmed to still be correct.", + "type": [ + "string" + ], + "format": "date-time" + }, + "status": { + "title": "Status", + "description": "The status that was realized on the date provided in `dateModified`, from the closed [milestoneStatus](https://standard.open-contracting.org/1.1/en/schema/codelists/#milestone-status) codelist.", + "type": [ + "string" + ], + "enum": [ + "scheduled", + "met", + "notMet", + "partiallyMet" + ], + "codelist": "milestoneStatus.csv", + "openCodelist": false + }, + "documents": { + "title": "Documents", + "description": "List of documents associated with this milestone (Deprecated in 1.1).", + "type": "array", + "items": { + "$ref": "#/definitions/Document" + }, + "uniqueItems": true, + "minItems": 1 + } + }, + "minProperties": 1 } }, "minProperties": 1 From 74c2ebd3f3a0f382a78ce6f33293b44d15c04f01 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 13:45:58 +1300 Subject: [PATCH 02/13] manage.py: Sort imports --- manage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manage.py b/manage.py index 01117bb7..0f6806e6 100755 --- a/manage.py +++ b/manage.py @@ -4,7 +4,7 @@ import re import sys import warnings -from collections import defaultdict, OrderedDict +from collections import OrderedDict, defaultdict from copy import deepcopy from io import StringIO from pathlib import Path From 2a17ce63ab3c93fe6d0cc6338e332a64d8c3c372 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 14:25:44 +1300 Subject: [PATCH 03/13] mapping/sustainability.yaml: Update disbursement records Add mapping and example --- docs/cost/common.md | 5 +++ docs/cost/ids/sustainability.md | 68 ++++++++++++++++++++++++++++++- mapping/sustainability.yaml | 72 ++++++++++++++++++++++++++++++++- 3 files changed, 141 insertions(+), 4 deletions(-) diff --git a/docs/cost/common.md b/docs/cost/common.md index c50c54a4..0faff9b3 100644 --- a/docs/cost/common.md +++ b/docs/cost/common.md @@ -17,3 +17,8 @@ Add a `Document` object to the `contractingProcesses.summary.documents` array an * Set its `.id` incrementally * Set its `.url` to a direct link to the document * Set its `.title` to the title of the document + +## Add an organization + +* Add an `Organization` object to the `.parties` array and set its `.name` to the name of the organization. +* If you collect organization identifiers, set `.identifier` according to the [identifier reference](../reference/schema.md#identifier) and set `.id` to {identifier.scheme}-{identifier.id}(-{department-identifier}). Otherwise, set `.id` incrementally. diff --git a/docs/cost/ids/sustainability.md b/docs/cost/ids/sustainability.md index fee65d6c..9993e321 100644 --- a/docs/cost/ids/sustainability.md +++ b/docs/cost/ids/sustainability.md @@ -1464,9 +1464,73 @@ Disbursements dates according to financial agreement versus actual disbursements :columns: 8 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 + +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 ```json - +{ + "milestones": [ + { + "id": "1", + "title": "Grant disbursement" + "status": "met", + "dueDate": "2023-07-01T00:00:00Z", + "dateMet": "2023-08-01T00:00:00Z", + "type": "payment", + "value": { + "amount": 5000000, + "currency": "USD" + } + } + ], + "transactions": [ + { + "id": "1", + "date": "2023-08-01T00:00:00Z", + "value": { + "amount": 5000000, + "currency": "USD" + }, + "payer": { + "id": "1", + "name": "United Nations Development Programme" + }, + "payee": { + "id": "2", + "name": "Ministry of works" + }, + "relatedImplementationMilestone": { + "id": "1", + "title": "Grant disbursement" + } + } + ] +} ``` ```` diff --git a/mapping/sustainability.yaml b/mapping/sustainability.yaml index dc3e9b12..6a06e6da 100644 --- a/mapping/sustainability.yaml +++ b/mapping/sustainability.yaml @@ -808,8 +808,76 @@ module: Climate finance indicator: Efficiency disclosure format: Disbursements dates according to financial agreement versus actual disbursements dates \[value, currency, date\] - mapping: '' - example: '' + 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 + + 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 + + + example: |- + { + "milestones": [ + { + "id": "1", + "title": "Grant disbursement" + "status": "met", + "dueDate": "2023-07-01T00:00:00Z", + "dateMet": "2023-08-01T00:00:00Z", + "type": "payment", + "value": { + "amount": 5000000, + "currency": "USD" + } + } + ], + "transactions": [ + { + "id": "1", + "date": "2023-08-01T00:00:00Z", + "value": { + "amount": 5000000, + "currency": "USD" + }, + "payer": { + "id": "1", + "name": "United Nations Development Programme" + }, + "payee": { + "id": "2", + "name": "Ministry of works" + }, + "relatedImplementationMilestone": { + "id": "1", + "title": "Grant disbursement" + } + } + ] + } - id: '3.21' title: Type of project monitoring module: Climate finance From 3fad9a6bee0917aa4201d56e58054c42d83dcd92 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 14:41:09 +1300 Subject: [PATCH 04/13] mapping/sustainability.yaml: Lint --- mapping/sustainability.yaml | 53 ++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/mapping/sustainability.yaml b/mapping/sustainability.yaml index 6a06e6da..2769e530 100644 --- a/mapping/sustainability.yaml +++ b/mapping/sustainability.yaml @@ -811,40 +811,45 @@ 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 + - 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: - * 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 + - 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 example: |- { "milestones": [ { "id": "1", - "title": "Grant disbursement" + "title": "Grant disbursement", "status": "met", "dueDate": "2023-07-01T00:00:00Z", "dateMet": "2023-08-01T00:00:00Z", From 109a024ba337ef29a77c97054d2b42bc63343345 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 15:07:19 +1300 Subject: [PATCH 05/13] schema/project-level/project-schema.json: Add field and definition Transaction.relatedImplementationMilestone and MilestoneReference --- manage.py | 12 ++++++++-- schema/project-level/project-schema.json | 30 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/manage.py b/manage.py index 0f6806e6..15eee79d 100755 --- a/manage.py +++ b/manage.py @@ -453,7 +453,7 @@ 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'}) + builder = ProfileBuilder('1__1__5', {'budget': 'master', 'transaction_milestones': 'master'}) ppp_schema = get(f'{ppp_base_url}release-schema.json').json() ppp_schema = builder.patched_release_schema(schema=ppp_schema) @@ -516,7 +516,8 @@ def copy_element(name, replacements=None, root='definitions'): 'Metric', 'Observation', 'Transaction', - 'Milestone' + 'Milestone', + 'MilestoneReference' } compare(schema['definitions'], infra_definitions, ocds_definitions, 'schema/project-level/project-schema.json#/definitions', 'definitions') @@ -739,6 +740,13 @@ def copy_element(name, replacements=None, root='definitions'): # Original from standard: "Milestone codes can be used to track specific events that take place for a particular kind of contracting process. For example, a code of 'approvalLetter' can be used to allow applications to understand this milestone represents the date an approvalLetter is due or signed." # noqa: E501 schema['definitions']['Milestone']['properties']['code']['description'] = "Milestone codes can be used to track specific events that take place for a particular kind of project or contracting process. For example, a code of 'approvalLetter' can be used to allow applications to understand this milestone represents the date an approvalLetter is due or signed." # noqa: E501 + copy_element('MilestoneReference', { + # Remove reference to release, add reference to project. + ('properties', 'id', 'description'): lambda s: s.replace(' described elsewhere in a release about this contracting process.', " in this project or contracting process's `.milestones`."), + }) + # 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 + remove_null_and_pattern_properties(schema) remove_integer_identifier_types(schema) remove_deprecated_properties(schema) diff --git a/schema/project-level/project-schema.json b/schema/project-level/project-schema.json index 62ad4a7e..915f613b 100644 --- a/schema/project-level/project-schema.json +++ b/schema/project-level/project-schema.json @@ -1850,6 +1850,11 @@ "string" ], "format": "uri" + }, + "relatedImplementationMilestone": { + "title": "Related implementation milestone", + "description": "A link to the milestone in the implementation section of OCDS to which this transaction relates.", + "$ref": "#/definitions/MilestoneReference" } }, "minProperties": 1 @@ -1978,6 +1983,31 @@ } }, "minProperties": 1 + }, + "MilestoneReference": { + "type": "object", + "title": "Milestone Reference", + "description": "A block used to reference a milestone, including the ID and title of the milestone being referenced.", + "required": [ + "id" + ], + "properties": { + "id": { + "title": "Milestone ID", + "description": "The ID of the milestone being referenced, this must match the ID of a milestone in this project or contracting process's `.milestones`.", + "type": "string", + "minLength": 1 + }, + "title": { + "title": "Milestone 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`.", + "type": [ + "string" + ], + "minLength": 1 + } + }, + "minProperties": 1 } }, "minProperties": 1 From 9c374135515841146933ea23f58c45cb81fd0363 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 15:08:31 +1300 Subject: [PATCH 06/13] docs/examples: Update examples --- docs/examples/blank.json | 54 ++++++++++++++++++++++++++++++++++++++ docs/examples/example.json | 44 ++++++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/docs/examples/blank.json b/docs/examples/blank.json index 4b5c512e..488b17a2 100644 --- a/docs/examples/blank.json +++ b/docs/examples/blank.json @@ -309,6 +309,23 @@ }, "uri": "string" } + ], + "milestones": [ + { + "id": "string", + "title": "string", + "type": "string from milestoneType codelist", + "description": "string", + "code": "string from milestoneCode codelist", + "dueDate": "string", + "dateMet": "string", + "dateModified": "string", + "status": "string from milestoneStatus codelist", + "relatedImplementationMilestone": { + "id": "string", + "title": "title" + } + } ] }, "releases": [ @@ -352,6 +369,43 @@ ] } ], + "transactions": [ + { + "id": "", + "source": "string", + "date": "string", + "value": { + "amount": "number", + "currency": "string from currency codelist" + }, + "payer": { + "name": "string", + "id": "" + }, + "payee": { + "name": "string", + "id": "" + }, + "uri": "string" + } + ], + "milestones": [ + { + "id": "string", + "title": "string", + "type": "string from milestoneType codelist", + "description": "string", + "code": "string from milestoneCode codelist", + "dueDate": "string", + "dateMet": "string", + "dateModified": "string", + "status": "string from milestoneStatus codelist", + "relatedImplementationMilestone": { + "id": "string", + "title": "title" + } + } + ], "completion": { "endDate": "", "endDateDetails": "", diff --git a/docs/examples/example.json b/docs/examples/example.json index 53233856..fa51a1d1 100644 --- a/docs/examples/example.json +++ b/docs/examples/example.json @@ -200,7 +200,8 @@ "procuringEntity", "buyer", "publicAuthority", - "funder" + "funder", + "payee" ], "people": [ { @@ -344,6 +345,11 @@ "jobTitle": "Commercial Contract Officer" } ] + }, + { + "id": "1", + "name": "United Nations Development Programme", + "roles": "payer" } ], "publicAuthority": { @@ -889,6 +895,42 @@ ] } ], + "milestones": [ + { + "id": "1", + "title": "Grant disbursement", + "status": "met", + "dueDate": "2016-01-01T00:00:00Z", + "dateMet": "2016-01-01T00:00:00Z", + "type": "payment", + "value": { + "amount": 5000000, + "currency": "GBP" + } + } + ], + "transactions": [ + { + "id": "1", + "date": "2016-01-01T00:00:00Z", + "value": { + "amount": 5000000, + "currency": "GBP" + }, + "payer": { + "id": "1", + "name": "United Nations Development Programme" + }, + "payee": { + "id": "GB-GOR-XX1234", + "name": "Motorways UK" + }, + "relatedImplementationMilestone": { + "id": "1", + "title": "Grant disbursement" + } + } + ], "completion": { "endDate": "2018-12-10T00:00:00Z", "endDateDetails": "Construction was delayed due to excavation problems when a watercourse was damaged.", From 9137b861a448d1be12714b3cb8956c6b1a27d5d5 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 15:12:10 +1300 Subject: [PATCH 07/13] schema/project-level/codelists: Add milestoneCode.csv --- manage.py | 5 +++-- schema/project-level/codelists/milestoneCode.csv | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 schema/project-level/codelists/milestoneCode.csv diff --git a/manage.py b/manage.py index 15eee79d..133605d2 100755 --- a/manage.py +++ b/manage.py @@ -488,6 +488,7 @@ def copy_element(name, replacements=None, root='definitions'): 'unitClassificationScheme.csv', 'milestoneType.csv', 'milestoneStatus.csv', + 'milestoneCode.csv' } compare([path.name for path in codelists_dir.iterdir()], infra_codelists, ocds_codelists, 'schema/project-level/codelists', 'codelists') @@ -742,10 +743,10 @@ def copy_element(name, replacements=None, root='definitions'): copy_element('MilestoneReference', { # Remove reference to release, add reference to project. - ('properties', 'id', 'description'): lambda s: s.replace(' described elsewhere in a release about this contracting process.', " in this project or contracting process's `.milestones`."), + ('properties', 'id', 'description'): lambda s: s.replace(' described elsewhere in a release about this contracting process.', " in this project or contracting process's `.milestones`."), # noqa: E501 }) # 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 + 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 remove_null_and_pattern_properties(schema) remove_integer_identifier_types(schema) diff --git a/schema/project-level/codelists/milestoneCode.csv b/schema/project-level/codelists/milestoneCode.csv new file mode 100644 index 00000000..b566d08b --- /dev/null +++ b/schema/project-level/codelists/milestoneCode.csv @@ -0,0 +1,10 @@ +Code,Title,Description,Extension +projectApproval,Project approval,The dates of approvals from relevant authorities.,OCDS for PPPs Extension +commercialClose,Commercial close,"In a financing, the point at which the commercial documentation has been executed but before conditions precedent have been satisfied or waived; before financial close.",OCDS for PPPs Extension +financialClose,Financial close,"In a financing, the point at which the documentation has been executed and conditions precedent have been satisfied or waived. Drawdowns become permissible after this point.",OCDS for PPPs Extension +commencement,Commencement of construction or development,The date of commencement of construction or development,OCDS for PPPs Extension +completion,Completion of construction of development,The date of completion of construction or development,OCDS for PPPs Extension +commissioning,Commissioning,The testing and inspection of the completed works to verify that the works are ready for commercial operation.,OCDS for PPPs Extension +enquiryPeriodStart,Enquiry period start,"For processes with multiple enquiry periods, the start date of a period during which enquiries can be made and responded to which is not provided in the tender/enquiryPeriod block. Sometimes known as clarification periods.",OCDS for PPPs Extension +enquiryPeriodEnd,Enquiry period end,"For processes with multiple enquiry periods, the end date of a period during which enquiries can be made and responded to which is not provided in the tender/enquiryPeriod block. Sometimes known as clarification periods.",OCDS for PPPs Extension +draftFinalTender,Submission of draft final tender,"For competitive dialogue processes, the deadline for submission of draft final tenders",OCDS for PPPs Extension From fbc6a8953586792b2a08f6fa2a28caf5ab2ed37f Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 15:13:09 +1300 Subject: [PATCH 08/13] Run ./manage.py pre-commit --- docs/_static/i18n.csv | 82 ++++++++++++++++++++++++++- docs/reference/schema.md | 119 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 196 insertions(+), 5 deletions(-) diff --git a/docs/_static/i18n.csv b/docs/_static/i18n.csv index d644ce56..bb5cfd8e 100644 --- a/docs/_static/i18n.csv +++ b/docs/_static/i18n.csv @@ -71,7 +71,6 @@ budget/budgetBreakdown/amount,Amount,False, budget/budgetBreakdown/amount,Value,False, budget/budgetBreakdown/amount/amount,Amount,False, budget/budgetBreakdown/amount/currency,Currency,False, -budget/budgetBreakdown/approvalDate,Approval date,False, budget/budgetBreakdown/uri,Linked budget information,False, budget/budgetBreakdown/period,Budget period,False, budget/budgetBreakdown/period,Period,False, @@ -79,10 +78,11 @@ budget/budgetBreakdown/period/startDate,Start date,False, budget/budgetBreakdown/period/endDate,End date,False, budget/budgetBreakdown/period/maxExtentDate,Maximum extent,False, budget/budgetBreakdown/period/durationInDays,Duration (days),False, -budget/budgetBreakdown/sourceParty,Source party,False, +budget/budgetBreakdown/sourceParty,Source organization,False, budget/budgetBreakdown/sourceParty,Organization reference,False, budget/budgetBreakdown/sourceParty/name,Organization name,True, budget/budgetBreakdown/sourceParty/id,Organization ID,True, +budget/budgetBreakdown/approvalDate,Approval date,False, forecasts,Forecasts,False, forecasts,Metric,False, forecasts/id,Identifier,False, @@ -275,6 +275,36 @@ contractingProcesses/summary/transactions/payee,Organization reference,False, contractingProcesses/summary/transactions/payee/name,Organization name,True, contractingProcesses/summary/transactions/payee/id,Organization ID,True, contractingProcesses/summary/transactions/uri,Linked spending information,False, +contractingProcesses/summary/transactions/relatedImplementationMilestone,Related implementation milestone,False, +contractingProcesses/summary/transactions/relatedImplementationMilestone,Milestone Reference,False, +contractingProcesses/summary/transactions/relatedImplementationMilestone/id,Milestone ID,True, +contractingProcesses/summary/transactions/relatedImplementationMilestone/title,Milestone title,True, +contractingProcesses/summary/milestones,Milestones,False, +contractingProcesses/summary/milestones,Milestone,False, +contractingProcesses/summary/milestones/id,ID,True, +contractingProcesses/summary/milestones/title,Title,True, +contractingProcesses/summary/milestones/type,Milestone type,False, +contractingProcesses/summary/milestones/description,Description,True, +contractingProcesses/summary/milestones/code,Milestone code,False, +contractingProcesses/summary/milestones/dueDate,Due date,False, +contractingProcesses/summary/milestones/dateMet,Date met,False, +contractingProcesses/summary/milestones/dateModified,Date modified,False, +contractingProcesses/summary/milestones/status,Status,False, +contractingProcesses/summary/milestones/documents,Documents,False, +contractingProcesses/summary/milestones/documents,Document,False, +contractingProcesses/summary/milestones/documents/id,ID,True, +contractingProcesses/summary/milestones/documents/documentType,Document type,False, +contractingProcesses/summary/milestones/documents/title,Title,True, +contractingProcesses/summary/milestones/documents/description,Description,True, +contractingProcesses/summary/milestones/documents/url,URL,False, +contractingProcesses/summary/milestones/documents/datePublished,Date published,False, +contractingProcesses/summary/milestones/documents/dateModified,Date modified,False, +contractingProcesses/summary/milestones/documents/format,Format,True, +contractingProcesses/summary/milestones/documents/language,Language,True, +contractingProcesses/summary/milestones/documents/pageStart,Page start,True, +contractingProcesses/summary/milestones/documents/pageEnd,Page end,True, +contractingProcesses/summary/milestones/documents/accessDetails,Access details,True, +contractingProcesses/summary/milestones/documents/author,Author,True, contractingProcesses/releases,Linked releases,False, contractingProcesses/releases,Release,False, contractingProcesses/releases/id,ID,True, @@ -307,6 +337,54 @@ metrics/observations/unit/id,ID,True, metrics/observations/unit/uri,URI,False, metrics/observations/dimensions,Dimensions,False, metrics/observations/notes,Notes,True, +transactions,Transactions,False, +transactions,Transaction information,False, +transactions/id,ID,True, +transactions/source,Data source,False, +transactions/date,Date,False, +transactions/value,Value,False, +transactions/value,Value,False, +transactions/value/amount,Amount,False, +transactions/value/currency,Currency,False, +transactions/payer,Payer,False, +transactions/payer,Organization reference,False, +transactions/payer/name,Organization name,True, +transactions/payer/id,Organization ID,True, +transactions/payee,Payee,False, +transactions/payee,Organization reference,False, +transactions/payee/name,Organization name,True, +transactions/payee/id,Organization ID,True, +transactions/uri,Linked spending information,False, +transactions/relatedImplementationMilestone,Related implementation milestone,False, +transactions/relatedImplementationMilestone,Milestone Reference,False, +transactions/relatedImplementationMilestone/id,Milestone ID,True, +transactions/relatedImplementationMilestone/title,Milestone title,True, +milestones,Milestones,False, +milestones,Milestone,False, +milestones/id,ID,True, +milestones/title,Title,True, +milestones/type,Milestone type,False, +milestones/description,Description,True, +milestones/code,Milestone code,False, +milestones/dueDate,Due date,False, +milestones/dateMet,Date met,False, +milestones/dateModified,Date modified,False, +milestones/status,Status,False, +milestones/documents,Documents,False, +milestones/documents,Document,False, +milestones/documents/id,ID,True, +milestones/documents/documentType,Document type,False, +milestones/documents/title,Title,True, +milestones/documents/description,Description,True, +milestones/documents/url,URL,False, +milestones/documents/datePublished,Date published,False, +milestones/documents/dateModified,Date modified,False, +milestones/documents/format,Format,True, +milestones/documents/language,Language,True, +milestones/documents/pageStart,Page start,True, +milestones/documents/pageEnd,Page end,True, +milestones/documents/accessDetails,Access details,True, +milestones/documents/author,Author,True, completion,Completion,False, completion/endDate,End date,False, completion/endDateDetails,End date details,True, diff --git a/docs/reference/schema.md b/docs/reference/schema.md index b4fe3c15..309cc8d4 100644 --- a/docs/reference/schema.md +++ b/docs/reference/schema.md @@ -110,7 +110,7 @@ Each `ContractingProcessSummary` has the following fields: ```{jsonschema} ../../build/current_lang/project-schema.json :pointer: /definitions/ContractingProcessSummary -:collapse: ocid,externalReference,nature,title,description,status,suppliers,contractValue,contractPeriod,finalValue,documents,modifications,transactions +:collapse: ocid,externalReference,nature,title,description,status,suppliers,contractValue,contractPeriod,finalValue,documents,modifications,transactions,milestones :addtargets: ``` @@ -424,6 +424,11 @@ Each `Value` has the following fields: :title: contractingProcesses/0/summary/transactions/0/value ``` +```{jsoninclude} ../../docs/examples/example.json +:jsonpointer: /projects/0/transactions/0/value +:title: transactions/0/value +``` + ```{jsoninclude} ../../docs/examples/example.json :jsonpointer: /projects/0/completion/finalValue :title: completion/finalValue @@ -541,6 +546,16 @@ Each `OrganizationReference` has the following fields: :title: contractingProcesses/0/summary/transactions/0/payee ``` +```{jsoninclude} ../../docs/examples/example.json +:jsonpointer: /projects/0/transactions/0/payer +:title: transactions/0/payer +``` + +```{jsoninclude} ../../docs/examples/example.json +:jsonpointer: /projects/0/transactions/0/payee +:title: transactions/0/payee +``` + ```` ````` @@ -645,7 +660,7 @@ Each `BudgetBreakdown` has the following fields: ```{jsonschema} ../../build/current_lang/project-schema.json :pointer: /definitions/BudgetBreakdown -:collapse: id,description,amount,approvalDate,uri,period,sourceParty +:collapse: id,description,amount,uri,period,sourceParty,approvalDate :addtargets: ``` @@ -672,6 +687,7 @@ Each `BudgetBreakdown` has the following fields: This sub-schema is referenced by the following properties: * [`documents`](project-schema.json,,documents) * [`ContractingProcessSummary/documents`](project-schema.json,/definitions/ContractingProcessSummary,documents) +* [`Milestone/documents`](project-schema.json,/definitions/Milestone,documents) Each `Document` has the following fields: @@ -699,6 +715,16 @@ Each `Document` has the following fields: :title: contractingProcesses/0/summary/documents ``` +```{jsoninclude} ../../docs/examples/example.json +:jsonpointer: /projects/0/contractingProcesses/0/summary/milestones/0/documents +:title: contractingProcesses/0/summary/milestones/0/documents +``` + +```{jsoninclude} ../../docs/examples/example.json +:jsonpointer: /projects/0/milestones/0/documents +:title: milestones/0/documents +``` + ```` ````` @@ -913,6 +939,7 @@ A spending transaction related to a contracting process. ``` This sub-schema is referenced by the following properties: +* [`transactions`](project-schema.json,,transactions) * [`ContractingProcessSummary/transactions`](project-schema.json,/definitions/ContractingProcessSummary,transactions) Each `Transaction` has the following fields: @@ -923,7 +950,7 @@ Each `Transaction` has the following fields: ```{jsonschema} ../../build/current_lang/project-schema.json :pointer: /definitions/Transaction -:collapse: id,source,date,value,payer,payee,uri +:collapse: id,source,date,value,payer,payee,uri,relatedImplementationMilestone :addtargets: ``` @@ -936,6 +963,11 @@ Each `Transaction` has the following fields: :title: contractingProcesses/0/summary/transactions ``` +```{jsoninclude} ../../docs/examples/example.json +:jsonpointer: /projects/0/transactions +:title: transactions +``` + ```` ````` @@ -974,3 +1006,84 @@ Each `SimpleIdentifier` has the following fields: ```` ````` + +### Milestone + +`Milestone` is defined as: + +```{field-description} ../../build/current_lang/project-schema.json /definitions/Milestone +``` + +This sub-schema is referenced by the following properties: +* [`milestones`](project-schema.json,,milestones) +* [`ContractingProcessSummary/milestones`](project-schema.json,/definitions/ContractingProcessSummary,milestones) + +Each `Milestone` has the following fields: + +`````{tab-set} + +````{tab-item} Schema + +```{jsonschema} ../../build/current_lang/project-schema.json +:pointer: /definitions/Milestone +:collapse: id,title,type,description,code,dueDate,dateMet,dateModified,status,documents +:addtargets: +``` + +```` + +````{tab-item} Examples + +```{jsoninclude} ../../docs/examples/example.json +:jsonpointer: /projects/0/contractingProcesses/0/summary/milestones +:title: contractingProcesses/0/summary/milestones +``` + +```{jsoninclude} ../../docs/examples/example.json +:jsonpointer: /projects/0/milestones +:title: milestones +``` + +```` + +````` + +### MilestoneReference + +`MilestoneReference` is defined as: + +```{field-description} ../../build/current_lang/project-schema.json /definitions/MilestoneReference +``` + +This sub-schema is referenced by the following properties: +* [`Transaction/relatedImplementationMilestone`](project-schema.json,/definitions/Transaction,relatedImplementationMilestone) + +Each `MilestoneReference` has the following fields: + +`````{tab-set} + +````{tab-item} Schema + +```{jsonschema} ../../build/current_lang/project-schema.json +:pointer: /definitions/MilestoneReference +:collapse: id,title +:addtargets: +``` + +```` + +````{tab-item} Examples + +```{jsoninclude} ../../docs/examples/example.json +:jsonpointer: /projects/0/contractingProcesses/0/summary/transactions/0/relatedImplementationMilestone +:title: contractingProcesses/0/summary/transactions/0/relatedImplementationMilestone +``` + +```{jsoninclude} ../../docs/examples/example.json +:jsonpointer: /projects/0/transactions/0/relatedImplementationMilestone +:title: transactions/0/relatedImplementationMilestone +``` + +```` + +````` From 897ec7100db2ccab06eaac16251f8e70acd9fe32 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 15:16:14 +1300 Subject: [PATCH 09/13] docs/reference/codelists.md: Add milestone codelists --- docs/reference/codelists.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/reference/codelists.md b/docs/reference/codelists.md index 9e1a260d..f1246301 100644 --- a/docs/reference/codelists.md +++ b/docs/reference/codelists.md @@ -25,6 +25,8 @@ OC4IDS reuses some codelists from the Open Contracting Data Standard and its ext * [Organization identifier scheme](https://standard.open-contracting.org/1.1/en/schema/codelists/#organization-identifier-scheme) * [Release tag](https://standard.open-contracting.org/1.1/en/schema/codelists/#release-tag) * [Unit classification scheme](https://standard.open-contracting.org/1.1/en/schema/codelists/#unit-classification-scheme) +* [Milestone status](https://standard.open-contracting.org/1.1/en/schema/codelists/#milestone-status) +* [Milestone code](https://standard.open-contracting.org/profiles/ppp/latest/en/reference/codelists/#milestonecode) ## Closed codelists @@ -58,6 +60,13 @@ Projects with a `status` of 'completed' may be displayed in a list of archived p :file: ../../build/current_lang/codelists/projectType.csv ``` +### MilestoneType + +```{csv-table-no-translate} +:header-rows: 1 +:file: ../../build/current_lang/codelists/milestoneType.csv +``` + ## Open codelists ### DocumentType From 748facf4d9195d7f9ebcbd2406d7193ca90a1fb3 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 15:20:21 +1300 Subject: [PATCH 10/13] docs/examples/example.json: Add contracting process milestones --- docs/examples/example.json | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/examples/example.json b/docs/examples/example.json index fa51a1d1..0e501ca7 100644 --- a/docs/examples/example.json +++ b/docs/examples/example.json @@ -555,6 +555,20 @@ "amount": 35250000, "currency": "GBP" }, + "milestones": [ + { + "id": "1", + "title": "Construction payment", + "status": "met", + "dueDate": "2017-08-07T00:00:00Z", + "dateMet": "2017-08-07T00:00:00Z", + "type": "payment", + "value": { + "amount": 1950000, + "currency": "GBP" + } + } + ], "transactions": [ { "id": "ocds-a1b1c1-c9b14c18-adc8-11e6-9901-0019b9f3037b-00001-1", @@ -572,7 +586,11 @@ "name": "Concrete Motorways Construction", "id": "GB-COH-33333333" }, - "uri": "https://openspending.org/motorways-uk-spending/transaction/xyz123" + "uri": "https://openspending.org/motorways-uk-spending/transaction/xyz123", + "relatedImplementationMilestone": { + "id": "1", + "title": "Construction payment" + } } ], "documents": [ From 2b96cd2ac64867bd567706065794713455d2cc84 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 15:21:21 +1300 Subject: [PATCH 11/13] schema/project-level/project-schema.json: Remove milestone documents --- docs/_static/i18n.csv | 30 ------------------------ docs/reference/schema.md | 13 +--------- manage.py | 2 ++ schema/project-level/project-schema.json | 10 -------- 4 files changed, 3 insertions(+), 52 deletions(-) diff --git a/docs/_static/i18n.csv b/docs/_static/i18n.csv index bb5cfd8e..45a581b6 100644 --- a/docs/_static/i18n.csv +++ b/docs/_static/i18n.csv @@ -290,21 +290,6 @@ contractingProcesses/summary/milestones/dueDate,Due date,False, contractingProcesses/summary/milestones/dateMet,Date met,False, contractingProcesses/summary/milestones/dateModified,Date modified,False, contractingProcesses/summary/milestones/status,Status,False, -contractingProcesses/summary/milestones/documents,Documents,False, -contractingProcesses/summary/milestones/documents,Document,False, -contractingProcesses/summary/milestones/documents/id,ID,True, -contractingProcesses/summary/milestones/documents/documentType,Document type,False, -contractingProcesses/summary/milestones/documents/title,Title,True, -contractingProcesses/summary/milestones/documents/description,Description,True, -contractingProcesses/summary/milestones/documents/url,URL,False, -contractingProcesses/summary/milestones/documents/datePublished,Date published,False, -contractingProcesses/summary/milestones/documents/dateModified,Date modified,False, -contractingProcesses/summary/milestones/documents/format,Format,True, -contractingProcesses/summary/milestones/documents/language,Language,True, -contractingProcesses/summary/milestones/documents/pageStart,Page start,True, -contractingProcesses/summary/milestones/documents/pageEnd,Page end,True, -contractingProcesses/summary/milestones/documents/accessDetails,Access details,True, -contractingProcesses/summary/milestones/documents/author,Author,True, contractingProcesses/releases,Linked releases,False, contractingProcesses/releases,Release,False, contractingProcesses/releases/id,ID,True, @@ -370,21 +355,6 @@ milestones/dueDate,Due date,False, milestones/dateMet,Date met,False, milestones/dateModified,Date modified,False, milestones/status,Status,False, -milestones/documents,Documents,False, -milestones/documents,Document,False, -milestones/documents/id,ID,True, -milestones/documents/documentType,Document type,False, -milestones/documents/title,Title,True, -milestones/documents/description,Description,True, -milestones/documents/url,URL,False, -milestones/documents/datePublished,Date published,False, -milestones/documents/dateModified,Date modified,False, -milestones/documents/format,Format,True, -milestones/documents/language,Language,True, -milestones/documents/pageStart,Page start,True, -milestones/documents/pageEnd,Page end,True, -milestones/documents/accessDetails,Access details,True, -milestones/documents/author,Author,True, completion,Completion,False, completion/endDate,End date,False, completion/endDateDetails,End date details,True, diff --git a/docs/reference/schema.md b/docs/reference/schema.md index 309cc8d4..23e72b19 100644 --- a/docs/reference/schema.md +++ b/docs/reference/schema.md @@ -687,7 +687,6 @@ Each `BudgetBreakdown` has the following fields: This sub-schema is referenced by the following properties: * [`documents`](project-schema.json,,documents) * [`ContractingProcessSummary/documents`](project-schema.json,/definitions/ContractingProcessSummary,documents) -* [`Milestone/documents`](project-schema.json,/definitions/Milestone,documents) Each `Document` has the following fields: @@ -715,16 +714,6 @@ Each `Document` has the following fields: :title: contractingProcesses/0/summary/documents ``` -```{jsoninclude} ../../docs/examples/example.json -:jsonpointer: /projects/0/contractingProcesses/0/summary/milestones/0/documents -:title: contractingProcesses/0/summary/milestones/0/documents -``` - -```{jsoninclude} ../../docs/examples/example.json -:jsonpointer: /projects/0/milestones/0/documents -:title: milestones/0/documents -``` - ```` ````` @@ -1026,7 +1015,7 @@ Each `Milestone` has the following fields: ```{jsonschema} ../../build/current_lang/project-schema.json :pointer: /definitions/Milestone -:collapse: id,title,type,description,code,dueDate,dateMet,dateModified,status,documents +:collapse: id,title,type,description,code,dueDate,dateMet,dateModified,status :addtargets: ``` diff --git a/manage.py b/manage.py index 133605d2..fcfb9d28 100755 --- a/manage.py +++ b/manage.py @@ -740,6 +740,8 @@ def copy_element(name, replacements=None, root='definitions'): schema['definitions']['Milestone']['properties']['id']['description'] = "A local identifier for this milestone, unique within this block." # noqa: E501 # Original from standard: "Milestone codes can be used to track specific events that take place for a particular kind of contracting process. For example, a code of 'approvalLetter' can be used to allow applications to understand this milestone represents the date an approvalLetter is due or signed." # noqa: E501 schema['definitions']['Milestone']['properties']['code']['description'] = "Milestone codes can be used to track specific events that take place for a particular kind of project or contracting process. For example, a code of 'approvalLetter' can be used to allow applications to understand this milestone represents the date an approvalLetter is due or signed." # noqa: E501 + # Remove deprecated milestone documents field + del schema['definitions']['Milestone']['properties']['documents'] copy_element('MilestoneReference', { # Remove reference to release, add reference to project. diff --git a/schema/project-level/project-schema.json b/schema/project-level/project-schema.json index 915f613b..31606722 100644 --- a/schema/project-level/project-schema.json +++ b/schema/project-level/project-schema.json @@ -1970,16 +1970,6 @@ ], "codelist": "milestoneStatus.csv", "openCodelist": false - }, - "documents": { - "title": "Documents", - "description": "List of documents associated with this milestone (Deprecated in 1.1).", - "type": "array", - "items": { - "$ref": "#/definitions/Document" - }, - "uniqueItems": true, - "minItems": 1 } }, "minProperties": 1 From 08215489e933c6651cbde6f5a91df8fde1078851 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Fri, 10 Nov 2023 15:26:26 +1300 Subject: [PATCH 12/13] Add changelog --- docs/reference/changelog.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/reference/changelog.md b/docs/reference/changelog.md index 3d1a076f..22cddd09 100644 --- a/docs/reference/changelog.md +++ b/docs/reference/changelog.md @@ -24,12 +24,20 @@ * [#379](https://github.com/open-contracting/infrastructure/pull/379) - add `contractingProcesses.summary.tender.datePublished`. * [#378](https://github.com/open-contracting/infrastructure/pull/378) - clarify semantics of `additionalClassifications`. * [#390](https://github.com/open-contracting/infrastructure/pull/390) - add `identifiers`. +* [#426](https://github.com/open-contracting/infrastructure/pull/426) - add fields: + * `.transactions` + * `.milestones` + * `ContractingProcesses.milestones` ### 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 ### Other From 55738b3023202d00a20b9a3f172ac10d04b62bf5 Mon Sep 17 00:00:00 2001 From: Duncan Dewhurst Date: Mon, 13 Nov 2023 09:09:58 +1300 Subject: [PATCH 13/13] Apply suggestions from code review Co-authored-by: James McKinney <26463+jpmckinney@users.noreply.github.com> --- manage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manage.py b/manage.py index fcfb9d28..072ce46e 100755 --- a/manage.py +++ b/manage.py @@ -488,7 +488,7 @@ def copy_element(name, replacements=None, root='definitions'): 'unitClassificationScheme.csv', 'milestoneType.csv', 'milestoneStatus.csv', - 'milestoneCode.csv' + 'milestoneCode.csv', } compare([path.name for path in codelists_dir.iterdir()], infra_codelists, ocds_codelists, 'schema/project-level/codelists', 'codelists') @@ -518,7 +518,7 @@ def copy_element(name, replacements=None, root='definitions'): 'Observation', 'Transaction', 'Milestone', - 'MilestoneReference' + 'MilestoneReference', } compare(schema['definitions'], infra_definitions, ocds_definitions, 'schema/project-level/project-schema.json#/definitions', 'definitions')