System for processing tenders and contracts via risk-rules and for assessing indicators of risks depending on tender/contract structure.
Risk rules are classes with particular properties and functions for processing object and assessing indicator.
All risk rules: src/prozorro/risks/rules
Base risk class: src/prozorro/risks/rules/base.py
Risk rule has next properties:
identifier
- Identifier of risk rule, e.g. "sas-3-1", "bank-3-3"name
- Risk name, e.g. "Невиконання замовником рішення органу оскарження"owner
- Risk owner, by default "sas"description
- Description of risk rulelegitimateness
- Legislative justification of the risk ruledevelopment_basis
- The basis for the development of the risk ruleprocurement_methods
- Possible procurement methods (procedure type). It is a set of strings:procurement_methods = ( "aboveThresholdEU", "aboveThresholdUA", "aboveThreshold", )
tender_statuses
- Set of tender statuses, on which risk rule is workingprocurement_categories
- Set of procurement categories, on which risk rule is workingprocuring_entity_kinds
- Set of procuring entity kind, on which risk rule is workingcontract_statuses
- Set of contract statuses, on which risk rule is working. This property is required for risk rules which process contracts and follow contract's APIstart_date
- Date from when risk rule has started. By default: "2023-01-01"end_date
- Date till what date risk rule is working. After that date risk rule will be turned off.stop_assessment_status
- Status on which risk rule stops processing tender and save previous result. For example for tenderstop_assessment_status = 'complete'
, for contractstop_assessment_status = 'terminated'
Each risk rule should have particular function for processing object whether the object for processing is a tender or a contract:
- process_tender
- process_contract
These functions have one required argument - JSON object (tender/contract body). And these functions should return one of 3 risk result classes:
RiskFound
- result where indicator is equal to 'risk_found'RiskNotFound
- result where indicator is equal to 'risk_not_found'RiskFromPreviousResult
- result where indicator is equal to 'use_previous_result'. This one is used when tender moves tostop_assessment_status
- e.g it can be 'complete' for tenders, 'terminated' for contracts. That means risk engine takes previous processing result and save it to database. After that object isn't being processed in the future. The processing is completed.
All these risk result classes have next properties:
- indicator
- type
- id
Properties type
and id
are optional. They should be set if risk rule processes particular item. Every risk rule for contract should return these two properties too. For example:
async def process_contract(self, contract):
...
return RiskFound(type="contract", id=contract["id"])
When type
and id
properties aren't set it means that tender has been processed in general.
- Create a new python file with naming as risk-identifier, in directory:
src/prozorro/risks/rules
E.g. new filesas-3-15.py
- Create class for risk rule and obligatory inherit from
BaseTenderRiskRule
orBaseContractRiskRule
(depends on what kind of object the risk-rule will be process)class RiskRule(BaseTenderRiskRule): ...
- Set all properties for your class (identifier, name, procurement_methods, etc.)
- Write logic for processing object in your class (functions
process_tender
orprocess_contract
). These functions should return onlyBaseRiskResult
instance (RiskFound, RiskNotFound, RiskFromPreviousResult). If your risk will be looking at particular items (not tender in general), then add to return resultstype
andid
of processing object (insideBaseRiskResult
).or for tender in general:async def process_contract(self, contract): ... return RiskFound(type="contract", id=contract["id"])
async def process_tender(self, tender): ... return RiskFound()
- TO TURN ON YOUR RISK FOR CRAWLER: Add your risk by file name to:
src/prozorro/risks/rules/__init__.py
. Happy testing!
Clone project on your local machine:
- via HTTPs: https://github.com/ProzorroUKR/prozorro-risks.git
- via CLI:
gh repo clone ProzorroUKR/prozorro-risks
Install next requirements on your machine:
- make
- docker
- docker-compose
To start the project in development mode, run the following command:
make run
or just
make start
To stop docker containers:
make stop
To clean up docker containers (removes containers, networks, volumes, and images created by docker-compose up):
make remove-compose
or just
make clean
Shell inside the running container
make bash # the command can be executed only if the server is running e.g. after `make run`
To run flake8:
make lint
All the settings for flake8
can be customized in .flake8
file
There are few env variables that can be configured in docker-compose.yaml for local deployment:
-
PUBLIC_API_HOST - link for tenders' and contracts' API host (e.g. 'https://api.prozorro.gov.ua')
-
FORWARD_CHANGES_COOLDOWN_SECONDS - time in seconds when crawler should stop processing. It may be needed for optimizing tender processing. Tenders may be modified too often, for instance every 5 minutes. This configuration allows crawler to wait and not process too fresh tenders that might be modified in the nearest future one more time. This configuration is in seconds. Crawler is watching at last dateModified of object in feed and if this date is less than
get_now - FORWARD_CHANGES_COOLDOWN_SECONDS
, than crawler goes to sleep.
E.g. to let crawler stop if dateModified less than get_now
for less than 10 hours:
FORWARD_CHANGES_COOLDOWN_SECONDS: '36000'
Or you can set FORWARD_CHANGES_COOLDOWN_SECONDS: ''
for crawler not to sleep.
- SLEEP_FORWARD_CHANGES_SECONDS - custom time in seconds for crawler to sleep after it stops (connects with
FORWARD_CHANGES_COOLDOWN_SECONDS
). Crawler is watching at last dateModified of object in feed and if this date is less thanget_now - FORWARD_CHANGES_COOLDOWN_SECONDS
, than crawler goes to sleep. By default crawler sleeps FORWARD_CHANGES_COOLDOWN_SECONDS, but if you want crawler sleeps less or more, you can configure it by variableSLEEP_FORWARD_CHANGES_SECONDS
To configure crawler to sleep 1 day:
For example, you can configure to stop crawler if dateModified greater that get_now - 31 days
and tell crawler to sleep 1 day before continuing processing:
FORWARD_CHANGES_COOLDOWN_SECONDS: '2678400'
SLEEP_FORWARD_CHANGES_SECONDS: '86400'
- FORWARD_OFFSET - timestamp from what period of time crawler starts processing tenders. E.g.
FORWARD_OFFSET: '1672524000.0' # 2023-01-01T00:00:00+02:00