Updated to Version 0.9.6 for public version

This commit is contained in:
Daniel Schick 2023-11-15 14:59:23 +01:00
parent e77c9264b9
commit 902cb9d90d
50 changed files with 1825 additions and 529 deletions

322
.gitignore vendored
View File

@ -1,44 +1,3 @@
Skip to content
Pull requests
Issues
Codespaces
Marketplace
Explore
@danielschick
github /
gitignore
Public
Fork your own copy of github/gitignore
Code
Pull requests 371
Actions
Security
Insights
Beta Try the new code view
gitignore/VisualStudio.gitignore
@n0099
n0099 [VisualStudio.gitignore] remove a trailing space
Latest commit 491040e Jan 26, 2022
History
165 contributors
@shiftkey
@arcresu
@aroben
@bbodenmiller
@HassanHashemi
@haacked
@niik
@AArnott
@sayedihashimi
@saschanaz
@bdougie
@OsirisTerje
398 lines (319 sloc) 6.7 KB
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
@ -75,40 +34,11 @@ bld/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
@ -139,20 +69,6 @@ StyleCopReport.xml
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
@ -162,108 +78,9 @@ ipch/
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
# *.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
@ -279,158 +96,33 @@ ClientBin/
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
.vscode/
#!.vscode/settings.json
#!.vscode/tasks.json
#!.vscode/launch.json
#!.vscode/extensions.json
#*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp

View File

@ -1,7 +1,7 @@
//----------------------
// <auto-generated>
// Generated REST API Client Code Generator v1.8.4.0 on 23.10.2023 09:06:40
// Generated REST API Client Code Generator v1.8.4.0 on 01.11.2023 15:27:09
// Using the tool OpenAPI Generator v7.0.0
// </auto-generated>
//----------------------

View File

@ -6,6 +6,14 @@ ___
## Client
Deployment of the productive client:
- create a branch release/pub_<version> from test release branch
- remove all text references to 'test' (changing target url in the process)
- rename application in settings
- change BG_COLOR in settings to #203864
- user deployment publish xml
## Database
## Backend / Flask app
@ -14,7 +22,7 @@ In order to not have complicated and error-prone copying manoevers a direct depl
### File structure
### Steps
### Installation steps
1) Created a ssh-key for the user that does the installation on the server following the Github [instructions](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent).
2) Deploy generated key to the Github user account.
@ -27,6 +35,8 @@ ssh-add ~/.ssh/od_ed25519
4) Change to deployment folder
e.g.
```bash
cd /var/www/brecal_test
```
@ -43,6 +53,12 @@ git checkout
6) Database credentials are stored outside the web root, we are using /var/www/secure. Here the file ```connection_data.json``` is placed, a different named copy for each instance.
### Changing Devel / Test / Prod Environment
Please note that in the "develop" branch the environment and paths are set to the "devel" setting. If a deployment is made (to testing or to the production) the scripts ```copytest.sh``` and ```copyprod.sh``` have to be run. These scripts will change the environment and paths to the respective settings.
There is also a script called ```bump-version.sh``` which can be used to upgrade all version entries in the repository.
### Installing Requirements
Python 3.11 & Pip3.11 installation (linux), virtualenv package

25
misc/bump-version.sh Normal file
View File

@ -0,0 +1,25 @@
#!/bin/bash
CURRENT_VERSION=$(cat version.txt)
NEW_VERSION="${1}"
if [ -z "${NEW_VERSION}" ]; then
echo "No new version given"
exit 1
fi
echo "Bumping version ${CURRENT_VERSION} to ${NEW_VERSION}"
CURRENT_VERSION=$(printf '%s\n' "$CURRENT_VERSION" | sed -e 's/[\/&]/\\&/g')
NEW_VERSION=$(printf '%s\n' "$NEW_VERSION" | sed -e 's/[\/&]/\\&/g')
echo "Found the following matching version strings:"
git grep -I "${CURRENT_VERSION}"
echo "Proceed? [N/y]"
read proceed
if [ "${proceed}" = "y" ]; then
git grep -Il "${CURRENT_VERSION}" | xargs sed --in-place -e "s/${CURRENT_VERSION}/${NEW_VERSION}/g"
git add $(git grep -Il "${NEW_VERSION}")
fi

42
misc/copyprod.sh Normal file
View File

@ -0,0 +1,42 @@
#!/bin/bash
# This script replaces all references to the development version with the test version
# 1) Database references and paths
git grep -I "connection_data_test.json" -- '..' ':(exclude)*.sh'
git grep -I "/var/www/brecal_test/" -- '..' ':(exclude)*.sh'
# 2) Color references
# Bar colors in client: (BG_COLOR)
# Devel: #1D751F
# Test: #751D1F
# Prod: #203864
git grep -I "#751D1F" -- '..' ':(exclude)*.sh'
# 3) Assembly name references
git grep -I "BreCalTestClient" -- '..' ':(exclude)*.sh'
echo "Proceed? [N/y]"
read proceed
# for color
if [ "${proceed}" = "y" ]; then
# 1. for database references and paths
git grep -I "connection_data_test.json" -- '..' ':(exclude)*.sh' | xargs sed --in-place -e "s/connection_data_test.json/connection_data_prod.json/g"
git add $(git grep -Il "connection_data_prod.json" -- '..' ':(exclude)*.sh')
git grep -I "/var/www/brecal_test/" -- '..' ':(exclude)*.sh' | xargs sed --in-place -e "s/\/var\/www\/brecal_test\//\/var\/www\/brecal\//g"
git add $(git grep -Il "/var/www/brecal/" -- '..' ':(exclude)*.sh')
# 2. for color
git grep -Il "#751D1F" -- '..' ':(exclude)*.sh' | xargs sed --in-place -e "s/#751D1F/#203864/g"
git add $(git grep -Il "#203864" -- '..' ':(exclude)*.sh')
# 3. for assembly name
git grep -I "BreCalTestClient" -- '..' ':(exclude)*.sh' | xargs sed --in-place -e "s/BreCalTestClient/BreCalClient/g"
git add $(git grep -Il "BreCalClient" -- '..' ':(exclude)*.sh')
fi

42
misc/copytest.sh Normal file
View File

@ -0,0 +1,42 @@
#!/bin/bash
# This script replaces all references to the development version with the test version
# 1) Database references and paths
git grep -I "connection_data_devel.json" -- '..' ':(exclude)*.sh'
git grep -I "/var/www/brecal_devel/" -- '..' ':(exclude)*.sh'
# 2) Color references
# Bar colors in client: (BG_COLOR)
# Devel: #1D751F
# Test: #751D1F
# Prod: #203864
git grep -I "#1D751F" -- '..' ':(exclude)*.sh'
# 3) Assembly name references
git grep -I "BreCalDevelClient" -- '..' ':(exclude)*.sh'
echo "Proceed? [N/y]"
read proceed
# for color
if [ "${proceed}" = "y" ]; then
# 1. for database references and paths
git grep -Il "connection_data_devel.json" -- '..' ':(exclude)*.sh' | xargs sed --in-place -e "s/connection_data_devel.json/connection_data_test.json/g"
git add $(git grep -Il "connection_data_test.json" -- '..' ':(exclude)*.sh')
git grep -Il "/var/www/brecal_devel/" -- '..' ':(exclude)*.sh' | xargs sed --in-place -e "s/\/var\/www\/brecal_devel\//\/var\/www\/brecal_test\//g"
git add $(git grep -Il "/var/www/brecal_test/" -- '..' ':(exclude)*.sh')
# 2. for color
git grep -Il "#1D751F" -- '..' ':(exclude)*.sh' | xargs sed --in-place -e "s/#1D751F/#751D1F/g"
git add $(git grep -Il "#751D1F" -- '..' ':(exclude)*.sh')
# 3. for assembly name
git grep -Il "BreCalDevelClient" -- '..' ':(exclude)*.sh' | xargs sed --in-place -e "s/BreCalDevelClient/BreCalTestClient/g"
git add $(git grep -Il "BreCalTestClient" -- '..' ':(exclude)*.sh')
fi

192
misc/sample_static_data.sql Normal file
View File

@ -0,0 +1,192 @@
-- --------------------------------------------------------
-- Host: 127.0.0.1
-- Server Version: 8.0.34-0ubuntu0.22.04.1 - (Ubuntu)
-- Server Betriebssystem: Linux
-- HeidiSQL Version: 10.2.0.5599
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-- Exportiere Daten aus Tabelle bremen_calling_test.berth: ~59 rows (ungefähr)
/*!40000 ALTER TABLE `berth` DISABLE KEYS */;
INSERT INTO `berth` (`id`, `name`, `lock`, `owner_id`, `authority_id`, `created`, `modified`, `deleted`) VALUES
(1, 'Roland Mühle', NULL, NULL, 11, '2023-06-26 14:01:40', '2023-10-06 15:04:08', b'1'),
(2, 'Stahlwerk', NULL, NULL, 11, '2023-06-26 14:01:40', '2023-10-06 15:04:08', b'1'),
(3, 'Kellogs', NULL, NULL, 11, '2023-06-26 14:01:40', '2023-10-06 15:04:08', b'1'),
(139, 'Avangard Dalben', NULL, 110, 136, '2023-08-21 08:23:35', '2023-10-06 16:06:01', b'0'),
(140, 'Avangard Kaje', NULL, 110, 11, '2023-08-21 08:23:35', '2023-10-06 15:04:08', b'0'),
(141, 'Baustelle 2', NULL, 111, 11, '2023-08-21 08:23:35', '2023-10-06 15:04:08', b'0'),
(142, 'BHW', NULL, 112, 11, '2023-08-21 08:23:36', '2023-10-06 15:04:08', b'0'),
(143, 'Dalben 2', NULL, 111, 11, '2023-08-21 08:23:36', '2023-10-06 15:04:08', b'0'),
(144, 'Dalben 3', NULL, 111, 11, '2023-08-21 08:23:36', '2023-10-06 15:04:08', b'0'),
(145, 'Egerland Kaje', NULL, 113, 11, '2023-08-21 08:23:36', '2023-10-06 15:04:08', b'0'),
(146, 'Getreideanlage Pier A', NULL, 114, 11, '2023-08-21 08:23:37', '2023-10-06 15:04:08', b'0'),
(147, 'Getreideanlage Pier D', NULL, 114, 11, '2023-08-21 08:23:37', '2023-10-06 15:04:08', b'0'),
(148, 'Griepe, Bnp Paribas', NULL, 115, 11, '2023-08-21 08:23:37', '2023-10-06 15:04:08', b'0'),
(149, 'Hafen F', NULL, 116, 11, '2023-08-21 08:23:37', '2023-10-06 15:04:08', b'0'),
(150, 'Hansa Landhandel', NULL, 117, 11, '2023-08-21 08:23:38', '2023-10-06 15:04:08', b'0'),
(151, 'Hansa Melasse', NULL, 118, 11, '2023-08-21 08:23:38', '2023-10-06 15:04:08', b'0'),
(152, 'Hansa-Mühle', NULL, 119, 11, '2023-08-21 08:23:38', '2023-10-06 15:04:08', b'0'),
(153, 'Heidelberger Sand', NULL, 120, 11, '2023-08-21 08:23:38', '2023-10-06 15:04:08', b'0'),
(154, 'HGM Bunkerstation', NULL, 121, 11, '2023-08-21 08:23:39', '2023-10-06 15:04:08', b'0'),
(155, 'HGM Tanklager', NULL, 121, 11, '2023-08-21 08:23:39', '2023-10-06 15:04:08', b'0'),
(156, 'Kap Horn Innen', NULL, 122, 11, '2023-08-21 08:23:39', '2023-10-06 15:04:08', b'0'),
(157, 'Kap Horn Weser', NULL, 122, 11, '2023-08-21 08:23:39', '2023-10-06 15:04:08', b'0'),
(158, 'Kap Horn Weser Bremer Recycling', NULL, 123, 11, '2023-08-21 08:23:40', '2023-10-06 15:04:08', b'0'),
(159, 'Kap Horn Weser -GHK-', NULL, 124, 11, '2023-08-21 08:23:40', '2023-10-06 15:04:08', b'0'),
(160, 'Kohlenhafen 2', NULL, 111, 11, '2023-08-21 08:23:40', '2023-10-06 15:04:08', b'0'),
(161, 'Kraftwerk Farge', NULL, 125, 11, '2023-08-21 08:23:40', '2023-10-06 15:04:08', b'0'),
(162, 'Kraftwerk Industriehafen', NULL, 126, 11, '2023-08-21 08:23:41', '2023-10-06 15:04:08', b'0'),
(163, 'Lankenau B', NULL, 111, 11, '2023-08-21 08:23:41', '2023-10-06 15:04:08', b'0'),
(164, 'Mibau, Bnp Paribas', NULL, 127, 11, '2023-08-21 08:23:41', '2023-10-06 15:04:08', b'0'),
(165, 'Müller Weser', NULL, 114, 11, '2023-08-21 08:23:41', '2023-10-06 15:04:08', b'0'),
(166, 'Osterort 5 Aussen', NULL, 111, 11, '2023-08-21 08:23:41', '2023-10-06 15:04:08', b'0'),
(167, 'Pier 2 Anleger', NULL, 128, 11, '2023-08-21 08:23:42', '2023-10-06 15:04:08', b'0'),
(168, 'Pier III', NULL, 129, 11, '2023-08-21 08:23:42', '2023-10-06 15:04:08', b'0'),
(169, 'Plump', NULL, 130, 11, '2023-08-21 08:23:42', '2023-10-06 15:04:08', b'0'),
(170, 'Rolandmühle', NULL, 131, 11, '2023-08-21 08:23:42', '2023-10-06 15:04:08', b'0'),
(171, 'Schleusenvorhafen Nord', NULL, 111, 11, '2023-08-21 08:23:43', '2023-10-06 15:04:08', b'0'),
(172, 'Schrägpier', NULL, 4, 11, '2023-08-21 08:23:43', '2023-10-06 15:04:08', b'0'),
(173, 'Schuppen 19', NULL, 132, 11, '2023-08-21 08:23:43', '2023-10-06 15:04:08', b'0'),
(174, 'Schuppen 20', NULL, 4, 11, '2023-08-21 08:23:43', '2023-10-06 15:04:08', b'0'),
(175, 'Schuppen 21', NULL, 4, 11, '2023-08-21 08:23:43', '2023-10-06 15:04:08', b'0'),
(176, 'Schuppen 22', NULL, 4, 11, '2023-08-21 08:23:43', '2023-10-06 15:04:08', b'0'),
(177, 'Schuppen 23', NULL, 4, 11, '2023-08-21 08:23:44', '2023-10-06 15:04:08', b'0'),
(178, 'Schuppen 24', NULL, 4, 11, '2023-08-21 08:23:44', '2023-10-06 15:04:08', b'0'),
(179, 'Seedalben Dlg-Seite', NULL, 111, 11, '2023-08-21 08:23:44', '2023-10-06 15:04:08', b'0'),
(180, 'Seedalben Kw-Seite', NULL, 111, 11, '2023-08-21 08:23:44', '2023-10-06 15:04:08', b'0'),
(181, 'Seehausen Spüler', NULL, 111, 11, '2023-08-21 08:23:44', '2023-10-06 15:04:08', b'0'),
(182, 'Tankschiffliegeplatz 1', NULL, 111, 11, '2023-08-21 08:23:44', '2023-10-06 15:04:08', b'0'),
(183, 'Tankschiffliegeplatz 2', NULL, 111, 11, '2023-08-21 08:23:44', '2023-10-06 15:04:08', b'0'),
(184, 'Terminal 1', NULL, 10, 11, '2023-08-21 08:23:44', '2023-10-06 15:04:08', b'0'),
(185, 'Terminal 2', NULL, 10, 11, '2023-08-21 08:23:45', '2023-10-06 15:04:08', b'0'),
(186, 'Terminal 3', NULL, 10, 11, '2023-08-21 08:23:45', '2023-10-06 15:04:08', b'0'),
(187, 'Terminal 4', NULL, 10, 11, '2023-08-21 08:23:45', '2023-10-06 15:04:08', b'0'),
(188, 'TSR Recycling', NULL, 133, 11, '2023-08-21 08:23:45', '2023-10-06 15:04:08', b'0'),
(189, 'Viehbrücke', NULL, 111, 11, '2023-08-21 08:23:45', '2023-10-06 15:04:08', b'0'),
(190, 'Vulkan Industriegebiet', NULL, 120, 11, '2023-08-21 08:23:46', '2023-10-06 15:04:08', b'0'),
(191, 'Weserbahnhof', NULL, 132, 11, '2023-08-21 08:23:46', '2023-10-06 15:04:08', b'0'),
(192, 'Weser-Petrol Holzhafen', NULL, 134, 11, '2023-08-21 08:23:46', '2023-10-06 15:04:08', b'0'),
(193, 'Weser-Petrol Kalihafen', NULL, 134, 11, '2023-08-21 08:23:46', '2023-10-06 15:04:08', b'0'),
(194, 'Wesertanking', NULL, 135, 11, '2023-08-21 08:23:46', '2023-10-06 15:04:08', b'0');
/*!40000 ALTER TABLE `berth` ENABLE KEYS */;
-- Exportiere Daten aus Tabelle bremen_calling_test.participant: ~40 rows (ungefähr)
/*!40000 ALTER TABLE `participant` DISABLE KEYS */;
INSERT INTO `participant` (`id`, `name`, `street`, `postal_code`, `city`, `type`, `flags`, `created`, `modified`, `deleted`) VALUES
(1, 'Schick Informatik', 'Gottlieb-Daimler-Str. 8', '73614', 'Schorndorf', 1, 42, '2023-04-17 07:18:19', '2023-08-24 07:07:02', b'0'),
(2, 'Lotsenbrüderschaft Weser 1', '', '', '', 4, 0, '2023-08-10 07:07:41', NULL, b'0'),
(3, 'Bremer Schiffsmeldedienst', 'Hafenkopf II / Überseetor 20', '28217', 'Bremen', 1, 0, '2023-08-10 07:11:10', NULL, b'0'),
(4, 'BLG Cargo Logistics GmbH', '', '', '', 2, 0, '2023-08-10 07:14:40', NULL, b'0'),
(5, 'Schiffsmakler-Verband für Küsten und Seeschiffsbefrachter e.V.', '', '', '', 8, 0, '2023-08-10 07:15:56', NULL, b'0'),
(6, 'RMS Rhenus Maritime Services GmbH', '', '', '', 8, 1, '2023-08-10 07:19:29', '2023-09-06 09:02:53', b'0'),
(7, 'J.MÜLLER Weser GmbH & Co. KG', '', '', '', 10, 0, '2023-08-10 07:21:43', '2023-08-10 08:47:59', b'0'),
(8, 'Schiffahrtskontor Detra GmbH & Co.KG', '', '', '', 8, 0, '2023-08-10 07:23:04', NULL, b'0'),
(9, 'Boluda Deutschland GmbH', '', '', '', 64, 0, '2023-08-10 07:24:18', NULL, b'0'),
(10, 'Weserport GmbH', '', '', '', 10, 0, '2023-08-10 07:26:42', '2023-08-10 08:48:19', b'0'),
(11, 'Port Authority Bremen', '', '', '', 32, 0, '2023-08-10 07:28:11', NULL, b'0'),
(12, 'Nordenia Frachtkontor GmbH', '', '', '', 8, 0, '2023-08-21 06:52:04', NULL, b'0'),
(15, 'Extern', '', '', '', 0, 0, '2023-08-21 06:55:18', NULL, b'0'),
(16, 'FESTMA Vertäugesellschaft mbH', '', '', '', 16, 0, '2023-08-21 06:57:23', NULL, b'0'),
(110, 'Avangard', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:35', '2023-08-21 10:04:21', b'0'),
(111, 'Bremenports', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:35', '2023-08-21 10:04:21', b'0'),
(112, 'Bremer Holzwerke', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:36', '2023-08-21 10:04:21', b'0'),
(113, 'Egerland', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:36', '2023-08-21 10:04:21', b'0'),
(114, 'Müller J. Bremen', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:37', '2023-08-21 10:04:21', b'0'),
(115, 'Griepe', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:37', '2023-08-21 10:04:21', b'0'),
(116, 'Mseven Real Estate', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:37', '2023-08-21 10:04:21', b'0'),
(117, 'Hansa Landhandel', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:38', '2023-08-21 10:04:21', b'0'),
(118, 'Hansa Melasse', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:38', '2023-08-21 10:04:21', b'0'),
(119, 'Hansa-Mühle', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:38', '2023-08-21 10:04:21', b'0'),
(120, 'Heidelberger Sand Und Kies Gmbh', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:38', '2023-08-21 10:04:21', b'0'),
(121, 'HGM', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:39', '2023-08-21 10:04:21', b'0'),
(122, 'Kap-Horn Logistics Gmbh', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:39', '2023-08-21 10:04:21', b'0'),
(123, 'Bremer Recycling Kontor', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:39', '2023-08-21 10:04:21', b'0'),
(124, 'GHK', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:40', '2023-08-21 10:04:21', b'0'),
(125, 'Kraftwerk Farge Engie Gmbh & Co. KG', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:40', '2023-08-21 10:04:21', b'0'),
(126, 'Swb Erzeugung', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:40', '2023-08-21 10:04:21', b'0'),
(127, 'Mibau', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:41', '2023-08-21 10:04:21', b'0'),
(128, 'SWG', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:41', '2023-08-21 10:04:21', b'0'),
(129, 'Umweltschutz Nord Ganderkesee', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:42', '2023-08-21 10:04:21', b'0'),
(130, 'Nehlsen Industrieservice Gmbh & Co. KG', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:42', '2023-08-21 10:04:21', b'0'),
(131, 'Rolandmühle', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:42', '2023-08-21 10:04:21', b'0'),
(132, 'Wfb', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:43', '2023-08-21 10:04:21', b'0'),
(133, 'TSR', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:45', '2023-08-21 10:04:21', b'0'),
(134, 'Weser-Petrol', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:46', '2023-08-21 10:04:21', b'0'),
(135, 'Wesertanking', NULL, NULL, NULL, 2, 0, '2023-08-21 08:23:46', '2023-08-21 10:04:21', b'0'),
(136, 'TEST_BSMD', 'Überseetor 20', '28217', 'Bremen', 127, 1, '2023-10-04 11:54:36', '2023-10-13 11:37:51', b'0');
/*!40000 ALTER TABLE `participant` ENABLE KEYS */;
-- Exportiere Daten aus Tabelle bremen_calling_test.role: ~2 rows (ungefähr)
/*!40000 ALTER TABLE `role` DISABLE KEYS */;
INSERT INTO `role` (`id`, `name`, `description`, `created`, `modified`) VALUES
(1, 'My first role', 'A very good description', '2023-04-17 07:31:57', NULL),
(2, 'Another role', 'This role is very nice as well', '2023-04-17 07:32:12', NULL);
/*!40000 ALTER TABLE `role` ENABLE KEYS */;
-- Exportiere Daten aus Tabelle bremen_calling_test.securable: ~2 rows (ungefähr)
/*!40000 ALTER TABLE `securable` DISABLE KEYS */;
INSERT INTO `securable` (`id`, `name`, `created`, `modified`) VALUES
(1, 'First secure thing', '2023-04-17 07:38:12', NULL),
(2, 'Another secure thing', '2023-04-17 07:38:22', NULL);
/*!40000 ALTER TABLE `securable` ENABLE KEYS */;
-- Exportiere Daten aus Tabelle bremen_calling_test.ship: ~12 rows (ungefähr)
/*!40000 ALTER TABLE `ship` DISABLE KEYS */;
INSERT INTO `ship` (`id`, `name`, `imo`, `callsign`, `participant_id`, `length`, `width`, `is_tug`, `bollard_pull`, `eni`, `created`, `modified`, `deleted`) VALUES
(1, 'Dicke Berta', 1234567, 'DEBE', 1, 100, 20, b'0', NULL, NULL, '2023-06-27 10:43:02', NULL, b'0'),
(2, 'Maersk Neston', 9632167, '9V3532', 1, 210.07, 30.2, b'0', NULL, NULL, '2023-07-27 12:34:13', NULL, b'0'),
(3, 'AFRICAN HALCYON', 9343613, NULL, NULL, 177.13, 28.4, b'0', NULL, NULL, '2023-08-24 10:41:56', NULL, b'0'),
(4, 'AMIKO', 9125669, NULL, NULL, 99.98, 16.5, b'0', NULL, NULL, '2023-08-24 10:42:17', NULL, b'0'),
(5, 'ARKLOW BEACON', 9638795, NULL, NULL, 119.49, 14.99, b'0', NULL, NULL, '2023-08-24 10:42:17', NULL, b'0'),
(6, 'FWN ATLANTIDE', 9535620, NULL, NULL, 145.65, 18.25, b'0', NULL, NULL, '2023-08-24 10:42:17', NULL, b'0'),
(7, 'IONIAN SPIRIT', 9747235, NULL, NULL, 179.9, 30, b'0', NULL, NULL, '2023-08-24 10:42:17', NULL, b'0'),
(8, 'IRMA', 9180396, NULL, NULL, 199.9, 23.6, b'0', NULL, NULL, '2023-08-24 10:42:17', NULL, b'0'),
(9, 'JANA', 9330185, NULL, NULL, 69.34, 12, b'0', NULL, NULL, '2023-08-24 10:42:18', NULL, b'0'),
(10, 'MEDI PERTH', 9804552, NULL, NULL, 199.99, 32.24, b'0', NULL, NULL, '2023-08-24 10:42:18', NULL, b'0'),
(11, 'S NEPTUNE', 9634892, NULL, NULL, 169.99, 27, b'0', NULL, NULL, '2023-08-24 10:42:18', NULL, b'0'),
(12, 'WESER STAHL', 9186687, NULL, NULL, 192, 32.26, b'0', NULL, NULL, '2023-08-24 10:42:18', NULL, b'0'),
(13, 'BOTHNIABORG', 9267728, 'PBIO', NULL, 153.05, 21.8, b'0', NULL, NULL, '2023-10-04 11:52:32', NULL, b'0');
/*!40000 ALTER TABLE `ship` ENABLE KEYS */;
-- Exportiere Daten aus Tabelle bremen_calling_test.user: ~27 rows (ungefähr)
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` (`id`, `participant_id`, `first_name`, `last_name`, `user_name`, `user_email`, `user_phone`, `password_hash`, `api_key`, `created`, `modified`) VALUES
(1, 1, 'Daniel', 'Schick', 'dani', NULL, NULL, '$2b$12$qfjw4b3XvGuu0t6HR8OYGOzF5b8gmC6PyIIBNbIXMXEayJunEEKmi', '0815', '2023-04-17 07:15:41', '2023-08-11 11:11:34'),
(2, 1, 'Londo', 'Mollari', 'Londo', 'l.mollari@centauri.gov', '+01 555 324 2314', '$2b$12$8r1oGQiWdiuQNoGbzm.z.OoCOc8.4YACN93k7ge7YDWKjQ8tPuTrm', NULL, '2023-06-27 08:34:55', '2023-10-28 12:04:54'),
(3, 2, 'Maik', 'Baudeck', 'maikb', NULL, NULL, '$2b$12$4SxGRlinOrpEVvqDZcE.wOusMZYsepdc6vj1vDpNhbPtApxU8VGPi', '', '2023-08-10 07:09:35', '2023-08-11 11:11:55'),
(4, 3, 'Christin', 'Hollmann', 'christinh', NULL, NULL, '$2b$12$evGJop3j19bNTkdg2GHrIeRedC7LG5SIHm8.hKhdUSrlXsp6sXBDG', '', '2023-08-10 07:12:05', '2023-10-04 11:48:13'),
(5, 3, 'Bastian', 'Güttner', 'bastiang', NULL, NULL, '$2b$12$0oCX3c2WyMykmxMoLqmpNubke713xhYlEEQgnxBV6Fj/TaUn.3/U6', '', '2023-08-10 07:12:26', '2023-08-11 11:11:13'),
(6, 3, 'Benjamin', 'Wiese', 'benjaminw', NULL, NULL, '$2b$12$RRj32KdLIf3D7z7cVWFqa.yZM5.ODOS0HqU3rdCuFrJS8HJ/rtqwy', '', '2023-08-10 07:13:01', '2023-08-11 11:11:16'),
(7, 1, 'Sladjan', 'Veselinovic', 'sladjanv', NULL, NULL, '$2b$12$4DctoCbZwxTvE39lXNRzneQ2kb/lXlJ5wEZ1CGbbw.rGM3nuAYjpa', '', '2023-08-10 07:13:39', '2023-08-11 11:11:45'),
(8, 1, 'Kersten', 'Gevers', 'kersteng', NULL, NULL, '$2b$12$zKX8iLPnXRmp5wD1Yp8P7e..U9R0A4ytbiMjd.l.IGkMzahcHPNWq', '', '2023-08-10 07:13:59', '2023-08-11 11:11:49'),
(9, 4, 'Dirk', 'Brunnert', 'dirkb', NULL, NULL, '$2b$12$HTeq/Fdfse6oElk7DLsQae5dtvWJloee.VtBH.THsj2kdcxxBkCDW', '', '2023-08-10 07:15:01', '2023-08-11 11:12:01'),
(10, 5, 'Thorsten', 'Fischer', 'thorstenf', NULL, NULL, '$2b$12$NHEpTNHuKU4ruPRIfd9yc.yv5faHGemFfRI3TISniqM7QNqHiyZpK', '', '2023-08-10 07:16:20', '2023-08-11 11:12:07'),
(11, 6, 'Lisa', 'Friedhoff', 'lisaf', NULL, NULL, '$2b$12$DJKJHGrQwfY9pwzgFfPds.DHGsygHyV3KDs38Hq4AUHPPs3jBPH3y', '', '2023-08-10 07:19:52', '2023-08-11 11:12:12'),
(12, 6, 'Dario', 'Fritschi', 'dariof', NULL, NULL, '$2b$12$MwCVTMQkN6zCAzCsE572Ye.M0nRDQNld4AgorLVyWq.DcQEmAy5lu', '', '2023-08-10 07:20:11', '2023-08-11 11:12:15'),
(13, 7, 'Hergen', 'Hanke', 'hergenh', NULL, NULL, '$2b$12$MKb6BDRrTbNd0qg5BdAS.upzlqxcWOgU/VEafJKSuzE9JLIWCimq6', '', '2023-08-10 07:22:09', '2023-08-11 11:12:24'),
(14, 8, 'Hardy', 'Paasch', 'hardyp', NULL, NULL, '$2b$12$l1lE/UqnYnOvci.N4j3zBOz6HC0z87ovnO0n6BIZYO7VN8gj.qGey', '', '2023-08-10 07:23:25', '2023-08-11 11:12:28'),
(15, 8, 'Marc', 'Pagel', 'marcp', NULL, NULL, '$2b$12$UCVJKzqX92Z8xZJ4kK0BRuFXMRdqcaXaGmBrqnYWARdKlPvZvLUZq', '', '2023-08-10 07:23:41', '2023-08-11 11:12:30'),
(16, 9, 'Andreas', 'Peukert', 'andreasp', NULL, NULL, '$2b$12$jNmciJAVR6p0IflvAthmk.j0SoOBvFHwDiEDKUHfwJq7baRsKg/LG', '', '2023-08-10 07:24:37', '2023-08-11 11:12:45'),
(17, 8, 'Christina', 'Rachiele', 'christinar', NULL, NULL, '$2b$12$BCsVgPRuIWPuuor07lprF.klQxvF901O3AXUhRrBJoEvYIjNQ.HKS', '', '2023-08-10 07:25:05', '2023-08-11 11:12:33'),
(18, 9, 'Sonia', 'Rekawek', 'soniar', NULL, NULL, '$2b$12$uHCkH6gu13yqllXBibLFIOWOpvctMC7NmojtXqDd6xsLq7bmvNOMu', '', '2023-08-10 07:25:27', '2023-08-11 11:12:48'),
(19, 6, 'Frank', 'Roelfs', 'frankr', NULL, NULL, '$2b$12$cEQAhUe9VJV6uTkfOY6/R.oAVfmFZQ4vS5G6BqoNEyaVHtFRDtB56', '', '2023-08-10 07:26:04', '2023-08-11 11:12:19'),
(20, 10, 'Vera', 'Schliedermann', 'veras', NULL, NULL, '$2b$12$FKcitW6W1HPwd.cdkZLGLeTFuzjsEIrbiKInysAKN.RibZ4gVLZHi', '', '2023-08-10 07:27:01', '2023-08-11 11:12:54'),
(21, 8, 'Michael', 'Strudthoff', 'michaels', NULL, NULL, '$2b$12$doTiywWpkso1UWB5eiAW1eoACP6rN4UDVt7qFFdRFvhhWUXikCmS2', '', '2023-08-10 07:27:27', '2023-08-11 11:12:37'),
(22, 4, 'Volker', 'Viohl', 'volkerv', NULL, NULL, '$2b$12$.YavQbWNE4eJDQA.ZNSKROYvMPWifBXyMX0IL0H2z50M720fpfTJW', '', '2023-08-10 07:27:50', '2023-08-11 11:12:04'),
(23, 11, 'Frauke', 'Zabel', 'fraukez', NULL, NULL, '$2b$12$rawQg6Cjl1yECGm9DOG8degdWdD.nZjEgGp8eXO98nh11QV1sEEEO', '', '2023-08-10 07:28:33', '2023-08-11 11:12:58'),
(24, 8, 'Jan', 'Zierow', 'janz', NULL, NULL, '$2b$12$CbnjUT42cf0mkIAqAURg3OksP9G3brmsE2GQTECTZ4.cVuhPn5D2G', '', '2023-08-10 07:28:55', '2023-08-11 11:12:39'),
(25, 12, 'Berit', 'Güstrau', 'beritg', NULL, NULL, '$2b$12$g8WJTEWwsrtMyqpVW/GFVuzyRjB2/n0YJJyvBx.3l51YiVEUjEQYy', '', '2023-08-21 06:52:35', NULL),
(26, 15, 'Ilknur', 'Colmorn', 'ilknurc', NULL, NULL, '$2b$12$tpEb0JQ8Li4YkPH28FeYk.1Jt2vK.TFn9SyhBKJ08gn7S5d8WYRlO', '', '2023-08-21 06:56:42', NULL),
(27, 16, 'Horst', 'Imgram', 'horsti', NULL, NULL, '$2b$12$05NFPSaP78puAa8pL39KrOKTafs/TzWwr4YfV4/Vrdu90assvNFZa', '', '2023-08-21 06:57:58', NULL),
(28, 136, 'Christin', 'Hollmann', 'chollmann', NULL, NULL, '$2b$12$pb1bWJ7hxOplFoqT/nIhyuRD39dxOpQ9t0LwZUI8CNOkTkE.eXiSO', '', '2023-10-04 11:55:05', NULL),
(29, 1, 'Max', 'Metz', 'maxm', NULL, NULL, '$2b$12$gm4EwjCF44Ls20vDHnlG/ew/cZ.DK4gcYed.OHER5J4OzZrA.9Jt.', '', '2023-10-06 13:02:56', '2023-10-13 11:53:35');
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

1
misc/version.txt Normal file
View File

@ -0,0 +1 @@
0.9.6.0

View File

@ -54,7 +54,7 @@
<xctk:WatermarkPasswordBox Watermark="{x:Static p:Resources.textOldPassword}" Grid.Column="1" Grid.Row="7" Margin="2" x:Name="wpBoxOldPassword" TextChanged="wpBoxOldPassword_TextChanged"/>
<xctk:WatermarkPasswordBox Watermark="{x:Static p:Resources.textNewPassword}" Grid.Column="1" Grid.Row="8" Margin="2" x:Name="wpBoxNewPassword" TextChanged="wpBoxOldPassword_TextChanged"/>
<xctk:WatermarkPasswordBox Watermark="{x:Static p:Resources.textRepeatNewPassword}" Grid.Column="1" Grid.Row="9" Margin="2" x:Name="wpBoxNewPasswordRepeat" TextChanged="wpBoxOldPassword_TextChanged"/>
<Button x:Name="buttonChangePassword" Click="buttonChangePassword_Click" Grid.Column="1" Grid.Row="10" Margin="2" Content="{x:Static p:Resources.textChange}" Width="80" HorizontalAlignment="Left" IsEnabled="False" />
<Button x:Name="buttonChangePassword" Click="buttonChangePassword_Click" Grid.Column="1" Grid.Row="10" Margin="2" Content="{x:Static p:Resources.textChange}" Width="80" HorizontalAlignment="Left" IsEnabled="True" />
<Button x:Name="buttonClose" Click="buttonClose_Click" Content="{x:Static p:Resources.textClose}" Width="80" Margin="2" Grid.Column="1" Grid.Row="12" HorizontalAlignment="Right" />

View File

@ -8,8 +8,8 @@
<SignAssembly>True</SignAssembly>
<StartupObject>BreCalClient.App</StartupObject>
<AssemblyOriginatorKeyFile>..\..\misc\brecal.snk</AssemblyOriginatorKeyFile>
<AssemblyVersion>0.9.4.0</AssemblyVersion>
<FileVersion>0.9.4.0</FileVersion>
<AssemblyVersion>0.9.6.0</AssemblyVersion>
<FileVersion>0.9.6.0</FileVersion>
<Title>Bremen calling client</Title>
<Description>A Windows WPF client for the Bremen calling API.</Description>
<ApplicationIcon>containership.ico</ApplicationIcon>

View File

@ -65,21 +65,20 @@
<ColumnDefinition Width=".5*" />
<ColumnDefinition Width=".5*" />
</Grid.ColumnDefinitions>
<ComboBox Name="comboBoxArrivalBerth" Grid.Column="1" Margin="2" DisplayMemberPath="Name" SelectedValuePath="Id">
<ComboBox.ContextMenu>
<ContextMenu>
<MenuItem Header="{x:Static p:Resources.textClearValue}" Name="contextMenuItemArrivalBerth" Click="contextMenuItemArrivalBerth_Click" />
</ContextMenu>
</ComboBox.ContextMenu>
</ComboBox>
<ComboBox Name="comboBoxDepartureBerth" Grid.Column="0" Margin="2" DisplayMemberPath="Name" SelectedValuePath="Id">
<ComboBox Name="comboBoxArrivalBerth" Grid.Column="0" Margin="2" DisplayMemberPath="Name" SelectedValuePath="Id">
<ComboBox.ContextMenu>
<ContextMenu>
<MenuItem Header="{x:Static p:Resources.textClearValue}" Name="contextMenuItemDepartureBerth" Click="contextMenuItemDepartureBerth_Click" />
</ContextMenu>
</ComboBox.ContextMenu>
</ComboBox>
<ComboBox Name="comboBoxDepartureBerth" Grid.Column="1" Margin="2" DisplayMemberPath="Name" SelectedValuePath="Id">
<ComboBox.ContextMenu>
<ContextMenu>
<MenuItem Header="{x:Static p:Resources.textClearValue}" Name="contextMenuItemArrivalBerth" Click="contextMenuItemArrivalBerth_Click" />
</ContextMenu>
</ComboBox.ContextMenu>
</ComboBox>
</Grid>
<xctk:DateTimePicker x:Name="datePickerETA" Grid.Column="3" Grid.Row="2" Margin="2" Format="Custom" FormatString="dd.MM. yyyy HH:mm" IsEnabled="False"/>

View File

@ -159,9 +159,17 @@ namespace BreCalClient
this.ShipcallModel.Shipcall.ShipId = ((Ship)this.comboBoxShip.SelectedItem).Id;
this.ShipcallModel.Ship = (Ship)this.comboBoxShip.SelectedItem;
this.ShipcallModel.Shipcall.ArrivalBerthId = (this.comboBoxArrivalBerth.SelectedItem != null) ? ((Berth)this.comboBoxArrivalBerth.SelectedItem).Id : null;
this.ShipcallModel.Shipcall.DepartureBerthId = (this.comboBoxDepartureBerth.SelectedItem != null) ? ((Berth)this.comboBoxDepartureBerth.SelectedItem).Id : null;
if (this.ShipcallModel.Shipcall.Type != 3) // incoming, outgoing
{
this.ShipcallModel.Shipcall.ArrivalBerthId = (this.comboBoxArrivalBerth.SelectedItem != null) ? ((Berth)this.comboBoxArrivalBerth.SelectedItem).Id : null;
this.ShipcallModel.Shipcall.DepartureBerthId = (this.comboBoxDepartureBerth.SelectedItem != null) ? ((Berth)this.comboBoxDepartureBerth.SelectedItem).Id : null;
}
else // shifting
{
this.ShipcallModel.Shipcall.DepartureBerthId = (this.comboBoxArrivalBerth.SelectedItem != null) ? ((Berth)this.comboBoxArrivalBerth.SelectedItem).Id : null;
this.ShipcallModel.Shipcall.ArrivalBerthId = (this.comboBoxDepartureBerth.SelectedItem != null) ? ((Berth)this.comboBoxDepartureBerth.SelectedItem).Id : null;
}
Participant? participant;
participant = (Participant?)this.comboBoxAgency.SelectedItem;
@ -225,8 +233,17 @@ namespace BreCalClient
// this.textBoxVoyage.Text = this.ShipcallModel.Shipcall.Voyage;
this.datePickerETD.Value = this.ShipcallModel.Shipcall.Etd;
this.comboBoxShip.SelectedValue = this.ShipcallModel.Shipcall.ShipId;
this.comboBoxArrivalBerth.SelectedValue = this.ShipcallModel.Shipcall.ArrivalBerthId;
this.comboBoxDepartureBerth.SelectedValue = this.ShipcallModel.Shipcall.DepartureBerthId;
if (this.ShipcallModel.Shipcall.Type != 3) // incoming, outgoing
{
this.comboBoxArrivalBerth.SelectedValue = this.ShipcallModel.Shipcall.ArrivalBerthId;
this.comboBoxDepartureBerth.SelectedValue = this.ShipcallModel.Shipcall.DepartureBerthId;
}
else // shifting
{
this.comboBoxArrivalBerth.SelectedValue = this.ShipcallModel.Shipcall.DepartureBerthId;
this.comboBoxDepartureBerth.SelectedValue = this.ShipcallModel.Shipcall.ArrivalBerthId;
}
if (this.ShipcallModel.Shipcall.Participants == null) this.ShipcallModel.Shipcall.Participants = new();

View File

@ -46,7 +46,8 @@ namespace BreCalClient
this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
this.CopyToControls();
this.Title = this.ShipcallModel.Title;
Participant? p = null;
if(this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))

View File

@ -46,6 +46,8 @@ namespace BreCalClient
this.comboBoxDepartureBerth.ItemsSource = BreCalLists.Berths;
this.CopyToControls();
this.Title = this.ShipcallModel.Title;
Participant? p = null;
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);

View File

@ -47,6 +47,8 @@ namespace BreCalClient
this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
this.CopyToControls();
this.Title = this.ShipcallModel.Title;
Participant? p = null;
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);

View File

@ -13,7 +13,7 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".25*" />
<ColumnDefinition Width=".75*" />
<ColumnDefinition Width="40" />
<!--ColumnDefinition Width="40" /-->
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
@ -24,7 +24,7 @@
<RowDefinition Height="56" />
<RowDefinition Height="28" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="2" Content="{x:Static p:Resources.textFixed}" />
<!-- Label Grid.Row="0" Grid.Column="2" Content="{x:Static p:Resources.textFixed}" /-->
<Label Grid.Row="1" Grid.Column="0" Content="{x:Static p:Resources.textETABerth}" HorizontalContentAlignment="Right" />
<Label Grid.Row="2" Grid.Column="0" Content="{x:Static p:Resources.textETDBerth}" HorizontalContentAlignment="Right" />
<Label Grid.Row="3" Grid.Column="0" Content="{x:Static p:Resources.textLockTime}" HorizontalContentAlignment="Right" />
@ -43,7 +43,7 @@
</ContextMenu>
</xctk:DateTimePicker.ContextMenu>
</xctk:DateTimePicker>
<CheckBox IsEnabled="False" Grid.Row="1" Grid.Column="2" Margin="4,0,0,0" Name="checkBoxEtaBerthFixed" VerticalAlignment="Center" />
<!--CheckBox IsEnabled="False" Grid.Row="1" Grid.Column="2" Margin="4,0,0,0" Name="checkBoxEtaBerthFixed" VerticalAlignment="Center" /-->
<xctk:DateTimePicker IsEnabled="False" Grid.Row="2" Grid.Column="1" Margin="2" Name="datePickerETDBerth" Format="Custom" FormatString="dd.MM. yyyy HH:mm">
<xctk:DateTimePicker.ContextMenu>
<ContextMenu>
@ -55,7 +55,7 @@
</ContextMenu>
</xctk:DateTimePicker.ContextMenu>
</xctk:DateTimePicker>
<CheckBox IsEnabled="False" Grid.Row="2" Grid.Column="2" Margin="4,0,0,0" Name="checkBoxEtDBerthFixed" VerticalAlignment="Center" />
<!--CheckBox IsEnabled="False" Grid.Row="2" Grid.Column="2" Margin="4,0,0,0" Name="checkBoxEtDBerthFixed" VerticalAlignment="Center" /-->
<xctk:DateTimePicker IsEnabled="False" Grid.Row="3" Grid.Column="1" Margin="2" Name="datePickerLockTime" Format="Custom" FormatString="dd.MM. yyyy HH:mm">
<xctk:DateTimePicker.ContextMenu>
<ContextMenu>
@ -67,7 +67,7 @@
</ContextMenu>
</xctk:DateTimePicker.ContextMenu>
</xctk:DateTimePicker>
<CheckBox IsEnabled="False" Grid.Row="3" Grid.Column="2" Margin="4,0,0,0" Name="checkBoxLockTimeFixed" VerticalAlignment="Center" />
<!--CheckBox IsEnabled="False" Grid.Row="3" Grid.Column="2" Margin="4,0,0,0" Name="checkBoxLockTimeFixed" VerticalAlignment="Center" /-->
<xctk:DateTimePicker IsEnabled="False" Grid.Row="4" Grid.Column="1" Margin="2" Name="datePickerZoneEntry" Format="Custom" FormatString="dd.MM. yyyy HH:mm">
<xctk:DateTimePicker.ContextMenu>
<ContextMenu>
@ -79,7 +79,7 @@
</ContextMenu>
</xctk:DateTimePicker.ContextMenu>
</xctk:DateTimePicker>
<CheckBox IsEnabled="False" Grid.Row="4" Grid.Column="2" Margin="4,0,0,0" Name="checkBoxZoneEntryFixed" VerticalAlignment="Center" />
<!--CheckBox IsEnabled="False" Grid.Row="4" Grid.Column="2" Margin="4,0,0,0" Name="checkBoxZoneEntryFixed" VerticalAlignment="Center" /-->
<TextBox Grid.Row="5" Grid.Column="1" Margin="2" Name="textBoxRemarks" TextWrapping="Wrap" AcceptsReturn="True" SpellCheck.IsEnabled="True" AcceptsTab="True" IsEnabled="False"/>
<StackPanel Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Right">

View File

@ -25,7 +25,7 @@ namespace BreCalClient
#region Properties
public Times Times { get; set; } = new();
public Times Times { get; set; } = new();
public Extensions.TypeEnum CallType { get; set; }
@ -34,7 +34,7 @@ namespace BreCalClient
#region event handler
private void Window_Loaded(object sender, RoutedEventArgs e)
{
{
this.CopyToControls();
this.EnableControls();
}
@ -64,10 +64,10 @@ namespace BreCalClient
this.Times.LockTime = this.datePickerLockTime.Value;
this.Times.ZoneEntry = this.datePickerZoneEntry.Value;
this.Times.EtaBerthFixed = this.checkBoxEtaBerthFixed.IsChecked;
this.Times.EtdBerthFixed = this.checkBoxEtDBerthFixed.IsChecked;
this.Times.LockTimeFixed = this.checkBoxLockTimeFixed.IsChecked;
this.Times.ZoneEntryFixed = this.checkBoxZoneEntryFixed.IsChecked;
//this.Times.EtaBerthFixed = this.checkBoxEtaBerthFixed.IsChecked;
//this.Times.EtdBerthFixed = this.checkBoxEtDBerthFixed.IsChecked;
//this.Times.LockTimeFixed = this.checkBoxLockTimeFixed.IsChecked;
//this.Times.ZoneEntryFixed = this.checkBoxZoneEntryFixed.IsChecked;
}
private void CopyToControls()
@ -78,10 +78,10 @@ namespace BreCalClient
this.datePickerLockTime.Value = this.Times.LockTime;
this.datePickerZoneEntry.Value = this.Times.ZoneEntry;
this.checkBoxEtaBerthFixed.IsChecked = this.Times.EtaBerthFixed;
this.checkBoxEtDBerthFixed.IsChecked = this.Times.EtdBerthFixed;
this.checkBoxLockTimeFixed.IsChecked = this.Times.LockTimeFixed;
this.checkBoxZoneEntryFixed.IsChecked = this.Times.ZoneEntryFixed;
//this.checkBoxEtaBerthFixed.IsChecked = this.Times.EtaBerthFixed;
//this.checkBoxEtDBerthFixed.IsChecked = this.Times.EtdBerthFixed;
//this.checkBoxLockTimeFixed.IsChecked = this.Times.LockTimeFixed;
//this.checkBoxZoneEntryFixed.IsChecked = this.Times.ZoneEntryFixed;
}
private void EnableControls()
@ -94,25 +94,25 @@ namespace BreCalClient
case Extensions.ParticipantType.MOORING:
case Extensions.ParticipantType.PORT_ADMINISTRATION:
case Extensions.ParticipantType.TUG:
this.datePickerETABerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
this.checkBoxEtaBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
this.datePickerETABerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
//this.checkBoxEtaBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
this.datePickerETDBerth.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
this.checkBoxEtDBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
//this.checkBoxEtDBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
this.datePickerLockTime.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
this.checkBoxLockTimeFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
//this.checkBoxLockTimeFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
this.datePickerZoneEntry.IsEnabled = false;
this.checkBoxZoneEntryFixed.IsEnabled = false;
//this.checkBoxZoneEntryFixed.IsEnabled = false;
this.textBoxRemarks.IsEnabled = true;
break;
case Extensions.ParticipantType.PILOT:
this.datePickerETABerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
this.checkBoxEtaBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
this.datePickerETABerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
//this.checkBoxEtaBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
this.datePickerETDBerth.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
this.checkBoxEtDBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
//this.checkBoxEtDBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
this.datePickerLockTime.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
this.checkBoxLockTimeFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
//this.checkBoxLockTimeFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
this.datePickerZoneEntry.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
this.checkBoxZoneEntryFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
//this.checkBoxZoneEntryFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
this.textBoxRemarks.IsEnabled = true;
break;
}

View File

@ -96,11 +96,11 @@ namespace BreCalClient
{
if (this.Times.ParticipantId != App.Participant.Id) return;
this.datePickerOperationStart.IsEnabled = (CallType == Extensions.TypeEnum.Incoming) || (CallType == Extensions.TypeEnum.Shifting);
this.datePickerOperationStart.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
this.datePickerOperationEnd.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing) || (CallType == Extensions.TypeEnum.Shifting);
this.comboBoxBerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming) || (CallType == Extensions.TypeEnum.Shifting);
this.comboBoxPierside.IsEnabled = (CallType == Extensions.TypeEnum.Incoming) || (CallType == Extensions.TypeEnum.Shifting);
this.textBoxBerthRemarks.IsEnabled = (CallType == Extensions.TypeEnum.Incoming) || (CallType == Extensions.TypeEnum.Shifting);
this.comboBoxBerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
this.comboBoxPierside.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
this.textBoxBerthRemarks.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
this.textBoxRemarks.IsEnabled = true;
this.buttonOK.IsEnabled = true;
}

View File

@ -11,6 +11,8 @@ namespace BreCalClient
{
Times Times { get; set; }
string Title { get; set; }
Extensions.TypeEnum CallType { get; set; }
bool? ShowDialog();

View File

@ -46,7 +46,7 @@ namespace BreCalClient
private bool _refreshImmediately = false;
private bool? _showCanceled = null;
private SortOrder? _sortOrder;
private SortOrder _sortOrder = SortOrder.ETA_ETD;
private int searchPastDays = 0;
// private bool _filterChanged = false;
@ -90,6 +90,7 @@ namespace BreCalClient
Process.Start("explorer", Properties.Settings.Default.LOGO_IMAGE_URL);
};
this.comboBoxSortOrder.ItemsSource = Enum.GetValues(typeof(Extensions.SortOrder));
this.comboBoxSortOrder.SelectedIndex = (int)_sortOrder;
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
@ -415,8 +416,16 @@ namespace BreCalClient
Shipcall shipcall = scm.Shipcall;
if (BreCalLists.ShipLookupDict.ContainsKey(shipcall.ShipId))
scm.Ship = BreCalLists.ShipLookupDict[shipcall.ShipId];
if (BreCalLists.BerthLookupDict.ContainsKey(shipcall.ArrivalBerthId ?? 0))
scm.Berth = BreCalLists.BerthLookupDict[shipcall.ArrivalBerthId ?? 0].Name;
if (shipcall.Type == 1)
{
if (BreCalLists.BerthLookupDict.ContainsKey(shipcall.ArrivalBerthId ?? 0))
scm.Berth = BreCalLists.BerthLookupDict[shipcall.ArrivalBerthId ?? 0].Name;
}
else
{
if (BreCalLists.BerthLookupDict.ContainsKey(shipcall.DepartureBerthId ?? 0))
scm.Berth = BreCalLists.BerthLookupDict[shipcall.DepartureBerthId ?? 0].Name;
}
scm.AssignParticipants();
}
@ -511,31 +520,28 @@ namespace BreCalClient
{
_ = this._visibleControlModels.RemoveAll(x => x.Shipcall?.Canceled ?? false);
}
if (this._sortOrder != null)
{
switch(this._sortOrder)
{
case Extensions.SortOrder.SHIP_NAME:
this._visibleControlModels.Sort((x, y) => { if (x.Ship == null) return 0; if (y.Ship == null) return 0; return x.Ship.Name.CompareTo(y.Ship.Name); });
break;
case Extensions.SortOrder.MODIFIED:
this._visibleControlModels.Sort((x, y) => { if (x.Shipcall == null) return 0; if (y.Shipcall == null) return 0; return DateTime.Compare(x.Shipcall.Modified ?? x.Shipcall.Created, y.Shipcall.Modified ?? x.Shipcall.Created); });
break;
case Extensions.SortOrder.ETA_ETD:
this._visibleControlModels.Sort((x, y) =>
{
if (x.Shipcall == null) return 0;
if (y.Shipcall == null) return 0;
DateTime xDate = (x.Shipcall.Type == (int) Extensions.TypeEnum.Incoming) ? x.Shipcall.Eta ?? DateTime.Now : x.Shipcall.Etd ?? DateTime.Now;
DateTime yDate = (y.Shipcall.Type == (int) Extensions.TypeEnum.Incoming) ? y.Shipcall.Eta ?? DateTime.Now : y.Shipcall.Etd ?? DateTime.Now;
return DateTime.Compare(xDate, yDate);
});
break;
default:
break;
}
}
switch(this._sortOrder)
{
case Extensions.SortOrder.SHIP_NAME:
this._visibleControlModels.Sort((x, y) => { if (x.Ship == null) return 0; if (y.Ship == null) return 0; return x.Ship.Name.CompareTo(y.Ship.Name); });
break;
case Extensions.SortOrder.MODIFIED:
this._visibleControlModels.Sort((x, y) => { if (x.Shipcall == null) return 0; if (y.Shipcall == null) return 0; return DateTime.Compare(x.Shipcall.Modified ?? x.Shipcall.Created, y.Shipcall.Modified ?? x.Shipcall.Created); });
break;
case Extensions.SortOrder.ETA_ETD:
this._visibleControlModels.Sort((x, y) =>
{
if (x.Shipcall == null) return 0;
if (y.Shipcall == null) return 0;
DateTime xDate = (x.Shipcall.Type == (int) Extensions.TypeEnum.Incoming) ? x.Eta ?? DateTime.Now : x.Etd ?? DateTime.Now;
DateTime yDate = (y.Shipcall.Type == (int) Extensions.TypeEnum.Incoming) ? y.Eta ?? DateTime.Now : y.Etd ?? DateTime.Now;
return DateTime.Compare(xDate, yDate);
});
break;
default:
break;
}
}
@ -617,6 +623,7 @@ namespace BreCalClient
// show a dialog that lets the user create / update times for the given shipcall
IEditTimesControl etc = (participantType == ParticipantType.TERMINAL) ? new EditTimesTerminalControl() : new EditTimesControl();
etc.Title = obj.ShipcallControlModel.Title;
if(obj.ShipcallControlModel.Shipcall != null)
etc.CallType = (TypeEnum) obj.ShipcallControlModel.Shipcall.Type;

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>0.9.6.0</ApplicationVersion>
<BootstrapperEnabled>True</BootstrapperEnabled>
<Configuration>Debug</Configuration>
<CreateDesktopShortcut>True</CreateDesktopShortcut>
<CreateWebPageOnPublish>True</CreateWebPageOnPublish>
<ErrorReportUrl>https://www.textbausteine.net/</ErrorReportUrl>
<GenerateManifests>true</GenerateManifests>
<Install>True</Install>
<InstallFrom>Web</InstallFrom>
<InstallUrl>https://www.bsmd-emswe.eu/develclient/</InstallUrl>
<IsRevisionIncremented>False</IsRevisionIncremented>
<IsWebBootstrapper>True</IsWebBootstrapper>
<MapFileExtensions>True</MapFileExtensions>
<OpenBrowserOnPublish>False</OpenBrowserOnPublish>
<Platform>Any CPU</Platform>
<ProductName>Bremen calling development client</ProductName>
<PublishDir>bin\Debug\net6.0-windows\win-x64\app.publish\</PublishDir>
<PublishUrl>bin\publish.devel\</PublishUrl>
<PublisherName>Informatikbüro Daniel Schick</PublisherName>
<PublishProtocol>ClickOnce</PublishProtocol>
<PublishReadyToRun>True</PublishReadyToRun>
<PublishSingleFile>True</PublishSingleFile>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>True</SelfContained>
<SignatureAlgorithm>(none)</SignatureAlgorithm>
<SignManifests>False</SignManifests>
<SuiteName>Bremen calling</SuiteName>
<SupportUrl>https://www.textbausteine.net/</SupportUrl>
<TargetFramework>net6.0-windows</TargetFramework>
<UpdateEnabled>True</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateRequired>False</UpdateRequired>
<WebPageFileName>Publish.html</WebPageFileName>
</PropertyGroup>
<ItemGroup>
<PublishFile Include="containership.ico">
<Group>
</Group>
<TargetPath>
</TargetPath>
<PublishState>Include</PublishState>
<IncludeHash>true</IncludeHash>
<FileType>File</FileType>
</PublishFile>
</ItemGroup>
</Project>

View File

@ -5,7 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Project>
<PropertyGroup>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>0.9.4.0</ApplicationVersion>
<ApplicationVersion>0.9.6.0</ApplicationVersion>
<BootstrapperEnabled>False</BootstrapperEnabled>
<Configuration>Release</Configuration>
<CreateWebPageOnPublish>True</CreateWebPageOnPublish>
@ -19,12 +19,12 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<MapFileExtensions>True</MapFileExtensions>
<OpenBrowserOnPublish>False</OpenBrowserOnPublish>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\net6.0-windows\app.publish\</PublishDir>
<PublishDir>bin\Release\net6.0-windows\win-x64\app.publish\</PublishDir>
<PublishUrl>bin\publish\</PublishUrl>
<PublishProtocol>ClickOnce</PublishProtocol>
<PublishReadyToRun>False</PublishReadyToRun>
<PublishSingleFile>False</PublishSingleFile>
<SelfContained>False</SelfContained>
<PublishSingleFile>True</PublishSingleFile>
<SelfContained>True</SelfContained>
<SignatureAlgorithm>(none)</SignatureAlgorithm>
<SignManifests>False</SignManifests>
<TargetFramework>net6.0-windows</TargetFramework>
@ -38,11 +38,17 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PublisherName>Informatikbüro Daniel Schick</PublisherName>
<SuiteName>Bremen calling client</SuiteName>
<SupportUrl>https://www.bsmd-emswe.eu/</SupportUrl>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.NetCore.DesktopRuntime.6.0.x64">
<Install>true</Install>
<ProductName>.NET Desktop Runtime 6.0.16 (x64)</ProductName>
</BootstrapperPackage>
<PublishFile Include="containership.ico">
<Group>
</Group>
<TargetPath>
</TargetPath>
<PublishState>Include</PublishState>
<IncludeHash>true</IncludeHash>
<FileType>File</FileType>
</PublishFile>
</ItemGroup>
</Project>

View File

@ -5,11 +5,12 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Project>
<PropertyGroup>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>0.9.4.0</ApplicationVersion>
<BootstrapperEnabled>False</BootstrapperEnabled>
<ApplicationVersion>0.9.6.*</ApplicationVersion>
<BootstrapperEnabled>True</BootstrapperEnabled>
<Configuration>Debug</Configuration>
<CreateDesktopShortcut>True</CreateDesktopShortcut>
<CreateWebPageOnPublish>True</CreateWebPageOnPublish>
<ErrorReportUrl>http://www.textbausteine.net</ErrorReportUrl>
<ErrorReportUrl>https://www.textbausteine.net/</ErrorReportUrl>
<GenerateManifests>true</GenerateManifests>
<Install>True</Install>
<InstallFrom>Web</InstallFrom>

View File

@ -9,20 +9,20 @@
//------------------------------------------------------------------------------
namespace BreCalClient.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("https://brecal.bsmd-emswe.eu")]
@ -31,25 +31,25 @@ namespace BreCalClient.Properties {
return ((string)(this["API_URL"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("#751D1F")]
[global::System.Configuration.DefaultSettingValueAttribute("#203864")]
public string BG_COLOR {
get {
return ((string)(this["BG_COLOR"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("!!Bremen calling Testversion!!")]
[global::System.Configuration.DefaultSettingValueAttribute("Bremen calling")]
public string APP_TITLE {
get {
return ((string)(this["APP_TITLE"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("https://www.textbausteine.net/")]
@ -58,7 +58,7 @@ namespace BreCalClient.Properties {
return ((string)(this["LOGO_IMAGE_URL"]));
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]

View File

@ -6,10 +6,10 @@
<Value Profile="(Default)">https://brecal.bsmd-emswe.eu</Value>
</Setting>
<Setting Name="BG_COLOR" Type="System.String" Scope="Application">
<Value Profile="(Default)">#751D1F</Value>
<Value Profile="(Default)">#203864</Value>
</Setting>
<Setting Name="APP_TITLE" Type="System.String" Scope="Application">
<Value Profile="(Default)">!!Bremen calling Testversion!!</Value>
<Value Profile="(Default)">Bremen calling</Value>
</Setting>
<Setting Name="LOGO_IMAGE_URL" Type="System.String" Scope="Application">
<Value Profile="(Default)">https://www.textbausteine.net/</Value>

View File

@ -1,12 +1,12 @@
<UserControl x:Class="BreCalClient.ShipcallControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:p = "clr-namespace:BreCalClient.Resources"
xmlns:sets="clr-namespace:BreCalClient.Properties"
xmlns:db="clr-namespace:BreCalClient;assembly=BreCalClient"
mc:Ignorable="d"
xmlns:db="clr-namespace:BreCalClient;assembly=BreCalClient"
mc:Ignorable="d"
d:DesignHeight="120" d:DesignWidth="800" Loaded="UserControl_Loaded">
<Border BorderBrush="LightGray" Margin="1" BorderThickness="1">
<Grid>
@ -45,7 +45,7 @@
<ColumnDefinition Width="32" />
</Grid.ColumnDefinitions>
<Image Margin="2" Grid.Column="0" PreviewMouseUp="Image_PreviewMouseUp" x:Name="imageShipcallType" />
<Label Grid.Column="1" FontSize="12" x:Name="labelShipName" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
<Label Grid.Column="1" FontSize="12" x:Name="labelShipName" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" PreviewMouseUp="Image_PreviewMouseUp"/>
<Grid Grid.Column="2" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}">
<Image Grid.Column="3" Margin="2" x:Name="imageEvaluation" />
@ -81,23 +81,23 @@
<Viewbox Grid.Row="6" Grid.Column="1" HorizontalAlignment="Left">
<TextBlock x:Name="textBlockBerth" Padding="0" FontWeight="DemiBold" />
</Viewbox>
</Grid>
<Label Grid.Row="0" Grid.Column="1" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
<Label Grid.Row="0" Grid.Column="1" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelAgent" PreviewMouseUp="labelAgent_PreviewMouseUp"/>
<Label Grid.Row="0" Grid.Column="2" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
<Label Grid.Row="0" Grid.Column="2" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelMooring" PreviewMouseUp="labelMooring_PreviewMouseUp"/>
<Label Grid.Row="0" Grid.Column="3" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
<Label Grid.Row="0" Grid.Column="3" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelPortAuthority" PreviewMouseUp="labelPortAuthority_PreviewMouseUp" />
<Label Grid.Row="0" Grid.Column="4" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
<Label Grid.Row="0" Grid.Column="4" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelPilot" PreviewMouseUp="labelPilot_PreviewMouseUp"/>
<Label Grid.Row="0" Grid.Column="5" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
<Label Grid.Row="0" Grid.Column="5" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelTug" PreviewMouseUp="labelTug_PreviewMouseUp"/>
<Label Grid.Row="0" Grid.Column="6" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
<Label Grid.Row="0" Grid.Column="6" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelTerminal" PreviewMouseUp="labelTerminal_PreviewMouseUp" />
<!-- AGENCY -->
<Border Grid.Row="2" Grid.Column="1" BorderThickness="1, 0, 0, 0" BorderBrush="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" Padding="3,0,0,0">
<Grid>
@ -111,7 +111,7 @@
<RowDefinition Height="14" />
<RowDefinition Height=".5*" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content = "ETA" x:Name="labelETAETDAgent" Padding="0" VerticalContentAlignment="Center" />
<Label Grid.Row="1" Grid.Column="0" Content="{x:Static p:Resources.textRemarks}" Padding="0" VerticalContentAlignment="Center" FontSize="9"/>
<Label Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Content="{x:Static p:Resources.textBerth}" Padding="0" VerticalContentAlignment="Center" FontSize="9"/>

View File

@ -1,6 +1,6 @@
// Copyright (c) 2023 schick Informatik
// Description: Show general shipcall info
//
//
using BreCalClient.misc.Model;
using log4net;
@ -53,7 +53,7 @@ namespace BreCalClient
/// <summary>
/// this is our datasource
/// </summary>
public ShipcallControlModel? ShipcallControlModel { get; set; }
public ShipcallControlModel? ShipcallControlModel { get; set; }
#endregion
@ -71,26 +71,61 @@ namespace BreCalClient
name = _agency?.Name;
if (name != null) agentName = name;
this.labelAgent.Content = name ?? "- / -";
if(_agency == null)
{
// clear agency display controls
this.labelAgencyBerth.Content = "";
this.labelAgencyETAETDValue.Content = "";
this.textBlockAgencyRemarks.Text = "";
this.textBlockAgencyBerthRemarks.Text = "";
}
_mooring = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.MOORING);
name = _mooring?.Name;
this.labelMooring.Content = name ?? "- / -";
if(_mooring == null)
{
this.labelMooringETAETDValue.Content = "";
this.textBlockMooringRemarks.Text = "";
}
_pilot = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.PILOT);
name = _pilot?.Name;
this.labelPilot.Content = name ?? "- / - ";
if(_pilot == null)
{
this.labelPilotETAETDValue.Content = "";
this.textBlockPilotRemarks.Text = "";
}
_tug = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.TUG);
name = _tug?.Name;
this.labelTug.Content = name ?? "- / - ";
if(_tug == null)
{
this.labelTugETAETDValue.Content = "";
this.textBlockTugRemarks.Text = "";
}
_port_administration = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.PORT_ADMINISTRATION);
name = _port_administration?.Name;
this.labelPortAuthority.Content = name ?? "- / - ";
if(_port_administration == null)
{
this.labelPortAuthorityETAETDValue.Content = "";
this.textBlockPortAuthorityRemarks.Text = "";
}
_terminal = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.TERMINAL);
name = _terminal?.Name;
this.labelTerminal.Content = name ?? "- / - ";
if(_terminal == null)
{
this.textBlockTerminalRemarks.Text = "";
this.textBlockTerminalBerthRemarks.Text = "";
this.labelTerminalBerth.Content = "";
this.labelOperationsStart.Content = "";
}
if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.TERMINAL) && (App.Participant.Id == _terminal?.Id))
{
@ -171,9 +206,9 @@ namespace BreCalClient
ShipcallControlModel.TrafficLightMode resultColor = (ShipcallControlModel.TrafficLightMode) (this.ShipcallControlModel?.Shipcall?.Evaluation ?? 0); // der nullable Operator hier ist so doof, die VS validation blickts einfach nicht
switch (resultColor)
{
case ShipcallControlModel.TrafficLightMode.GREEN:
this.Background = Brushes.LightGreen;
break;
//case ShipcallControlModel.TrafficLightMode.GREEN:
// this.Background = Brushes.LightGreen;
// break;
case ShipcallControlModel.TrafficLightMode.YELLOW:
this.Background= Brushes.LightYellow;
break;
@ -191,7 +226,7 @@ namespace BreCalClient
this.textBlockBerth.Text = this.ShipcallControlModel?.Berth;
this.textBlockCallsign.Text = this.ShipcallControlModel?.Ship?.Callsign;
if (this.ShipcallControlModel?.Shipcall?.Type == 1)
if (this.ShipcallControlModel?.Shipcall?.Type == 1)
{
this.textBlockETA.Text = this.ShipcallControlModel?.Shipcall?.Eta?.ToString("dd.MM. HH:mm");
}
@ -204,7 +239,7 @@ namespace BreCalClient
this.textBlockIMO.Text = this.ShipcallControlModel?.Ship?.Imo.ToString();
this.textBlockLengthWidth.Text = $"{this.ShipcallControlModel?.Ship?.Length} / {this.ShipcallControlModel?.Ship?.Width}";
// rename labels if this is not an incoming
// rename labels if this is not an incoming
// must be here because there may not be a times record for each participant (yet)
if (this.ShipcallControlModel?.Shipcall?.Type != 1)
@ -222,12 +257,13 @@ namespace BreCalClient
foreach (Times times in this.ShipcallControlModel.Times)
{
string? berthText = null;
if ((BreCalLists.Berths != null) && times.BerthId.HasValue)
if ((BreCalLists.Berths != null) && times.BerthId.HasValue && (this.ShipcallControlModel?.Shipcall?.Type != (int) Extensions.TypeEnum.Shifting))
{
Berth? berth = BreCalLists.Berths.Find((x) => x.Id == times.BerthId);
berthText = berth?.Name;
}
if (berthText == null)
if ((berthText == null) && (times.ParticipantType != (int) Extensions.ParticipantType.TERMINAL))
{
if (this.ShipcallControlModel?.Shipcall?.Type == (int)Extensions.TypeEnum.Incoming)
{
@ -328,7 +364,7 @@ namespace BreCalClient
{
if(App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD))
this.EditRequested?.Invoke(this);
}
}
private void Image_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
@ -336,10 +372,10 @@ namespace BreCalClient
}
private void labelAgent_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
{
Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.AGENCY);
this.EditAgencyRequested?.Invoke(this, times);
}
this.EditAgencyRequested?.Invoke(this, times);
}
private void labelMooring_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
@ -349,7 +385,7 @@ namespace BreCalClient
private void labelPortAuthority_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PORT_ADMINISTRATION);
Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PORT_ADMINISTRATION);
this.EditTimesRequested?.Invoke(this, times, Extensions.ParticipantType.PORT_ADMINISTRATION);
}

View File

@ -52,6 +52,28 @@ namespace BreCalClient
public List<Times> Times { get; set; } = new();
public DateTime? Eta
{
get
{
Times? agencyTimes = this.GetTimesForParticipantType(Extensions.ParticipantType.AGENCY);
if((agencyTimes != null) && (agencyTimes.EtaBerth != null))
return agencyTimes.EtaBerth;
return Shipcall?.Eta;
}
}
public DateTime? Etd
{
get
{
Times? agencyTimes = this.GetTimesForParticipantType(Extensions.ParticipantType.AGENCY);
if ((agencyTimes != null) && (agencyTimes.EtdBerth != null))
return agencyTimes.EtdBerth;
return Shipcall?.Etd;
}
}
public TrafficLightMode LightMode
{
get
@ -69,6 +91,16 @@ namespace BreCalClient
}
}
public string Title
{
get
{
if (this.Shipcall == null) return "";
Extensions.TypeEnum callType = (Extensions.TypeEnum) this.Shipcall.Type;
return string.Format("{0} {1}", callType, this.Ship?.Name);
}
}
#endregion
#region public methods
@ -142,6 +174,33 @@ namespace BreCalClient
await _api.TimesPutAsync(times);
}
}
// if somebody just removed an assignment it is gone fom AssignedParticipants, but there is still a
// times record left which must be removed
List<Times> deleteTimes = new();
foreach (Times times in this.Times)
{
bool foundTimes = false;
foreach (ParticipantAssignment pa in this.AssignedParticipants.Values)
{
if((pa.ParticipantId == times.ParticipantId) && (pa.Type == times.ParticipantType))
{
foundTimes = true;
break;
}
}
if (!foundTimes)
{
deleteTimes.Add(times);
}
}
foreach(Times times in deleteTimes)
{
_api.TimesDelete(times.Id);
this.Times.Remove(times);
}
}
#endregion

View File

@ -13,6 +13,25 @@ from .api import ships
from .api import login
from .api import user
from BreCal.brecal_utils.file_handling import get_project_root, ensure_path
from BreCal.brecal_utils.test_handling import execute_test_with_pytest, execute_coverage_test
from BreCal.brecal_utils.time_handling import difference_to_then
from BreCal.validators.time_logic import TimeLogic
from BreCal.validators.validation_rules import ValidationRules
from BreCal.validators.schema_validation import validation_state_and_validation_name
from BreCal.stubs.times_agency import get_times_agency
from BreCal.stubs.times_bsmd import get_times_bsmd
from BreCal.stubs.times_mooring import get_times_mooring
from BreCal.stubs.times_pilot import get_times_pilot
from BreCal.stubs.times_portauthority import get_times_port_authority
from BreCal.stubs.times_terminal import get_times_terminal
from BreCal.stubs.times_tug import get_times_tug
from BreCal.stubs.times_full import get_times_full_simple
from BreCal.stubs.df_times import get_df_times
def create_app(test_config=None):
app = Flask(__name__, instance_relative_config=True)
@ -47,22 +66,24 @@ def create_app(test_config=None):
return app
from BreCal.brecal_utils.file_handling import get_project_root, ensure_path
from BreCal.brecal_utils.test_handling import execute_test_with_pytest, execute_coverage_test
from BreCal.brecal_utils.time_handling import difference_to_then
from BreCal.validators.time_logic import TimeLogic
from BreCal.validators.validation_rules import ValidationRules
from BreCal.validators.schema_validation import validation_state_and_validation_name
__all__ = [
"get_project_root",
"ensure_path",
"execute_test_with_pytest",
"execute_coverage_test",
"get_project_root",
"ensure_path",
"execute_test_with_pytest",
"execute_coverage_test",
"difference_to_then",
"TimeLogic",
"ValidationRules",
"validation_state_and_validation_name",
"get_times_agency",
"get_times_bsmd",
"get_times_mooring",
"get_times_pilot",
"get_times_port_authority",
"get_times_terminal",
"get_times_tug",
"get_times_full_simple",
"get_df_times",
]

View File

@ -26,7 +26,7 @@ class SQLHandler():
with self.sql_connection.cursor(buffered=True) as cursor:
cursor.execute("SHOW TABLES")
schema = cursor.fetchall()
all_schemas = [schem[0] for schem in schema]
all_schemas = [schem[0] for schem in schema]
return all_schemas
def build_str_to_model_dict(self):
@ -42,13 +42,51 @@ class SQLHandler():
def read_mysql_table_to_df(self, table_name:str):
"""determine a {table_name}, which will be read from a mysql server. returns a pandas DataFrame with the respective data"""
df = pd.read_sql(sql=f"SELECT * FROM {table_name}", con=self.sql_connection)
with self.sql_connection.cursor(buffered=True) as cursor: #df = pd.read_sql(sql=f"SELECT * FROM {table_name}", con=self.sql_connection)
# 1.) get the column names
cursor.execute(f"DESCRIBE {table_name}")
cols = cursor.fetchall()
column_names = [col_name[0] for col_name in cols]
# 2.) get the data tuples
cursor.execute(f"SELECT * FROM {table_name}")
data = cursor.fetchall()
# 3.) map the data tuples to the correct column names
data = [{k:v for k,v in zip(column_names, dat)} for dat in data]
# 4.) build a dataframe from the respective data models (which ensures the correct data type)
data_model = self.str_to_model_dict.get(table_name)
if data_model is not None:
df = pd.DataFrame([data_model(**dat) for dat in data])
else:
df = pd.DataFrame([dat for dat in data])
return df
def mysql_to_df(self, query):
def mysql_to_df(self, query, table_name):
"""provide an arbitrary sql query that should be read from a mysql server {sql_connection}. returns a pandas DataFrame with the obtained data"""
df = pd.read_sql(query, self.sql_connection).convert_dtypes()
df = df.set_index('id', inplace=False) # avoid inplace updates, so the raw sql remains unchanged
with self.sql_connection.cursor(buffered=True) as cursor: # df = pd.read_sql(query, self.sql_connection).convert_dtypes()
# 1.) get the column names
cursor.execute(f"DESCRIBE {table_name}")
cols = cursor.fetchall()
column_names = [col_name[0] for col_name in cols]
# 2.) get the data tuples
cursor.execute(query)
data = cursor.fetchall()
# 3.) map the data tuples to the correct column names
data = [{k:v for k,v in zip(column_names, dat)} for dat in data]
# 4.) build a dataframe from the respective data models (which ensures the correct data type)
data_model = self.str_to_model_dict.get(table_name)
if data_model is not None:
df = pd.DataFrame([data_model(**dat) for dat in data])
else:
df = pd.DataFrame([dat for dat in data])
if 'id' in df.columns:
df = df.set_index('id', inplace=False) # avoid inplace updates, so the raw sql remains unchanged
return df
def read_all(self, all_schemas):
@ -64,7 +102,7 @@ class SQLHandler():
mysql_df_dict = {}
for schem in all_schemas:
query = f"SELECT * FROM {schem}"
mysql_df_dict[schem] = self.mysql_to_df(query)
mysql_df_dict[schem] = self.mysql_to_df(query, table_name=schem)
return mysql_df_dict
def initialize_shipcall_participant_list(self):
@ -183,6 +221,9 @@ class SQLHandler():
# filter out all NaN and NaT entries
if non_null_column is not None:
# in the Pandas documentation, it says for .isnull():
# "This function takes a scalar or array-like object and indicates whether values are missing
# (NaN in numeric arrays, None or NaN in object arrays, NaT in datetimelike)."
df_times = df_times.loc[~df_times[non_null_column].isnull()] # NOT null filter
# filter by the agency participant_type
@ -192,13 +233,20 @@ class SQLHandler():
def filter_df_by_key_value(self, df, key, value)->pd.DataFrame:
return df.loc[df[key]==value]
def get_unique_ship_counts(self, all_df_times:pd.DataFrame, query:str, rounding:str="min", maximum_threshold=3):
def get_unique_ship_counts(self, all_df_times:pd.DataFrame, times_agency:pd.DataFrame, query:str, rounding:str="min", maximum_threshold=3):
"""given a dataframe of all agency times, get all unique ship counts, their values (datetime) and the string tags. returns a tuple (values,unique,counts)"""
# get values and optional: rounding
values = all_df_times.loc[:, query]
# optional: rounding
if rounding is not None:
values = values.dt.round(rounding) # e.g., 'min'
all_df_times.loc[:, query] = all_df_times.loc[:, query].dt.round(rounding) # e.g., 'min'
query_time_agency = times_agency[query].iloc[0].round(rounding)# e.g., 'min'
unique, counts = np.unique(values, return_counts=True)
violation_state = np.any(np.greater(counts, maximum_threshold))
return (values, unique, counts)
# after rounding, filter {all_df_times}, so only those, which match the current query are of interest
# takes 'times_agency' to sample, which value should match
all_df_times = all_df_times.loc[all_df_times[query]==query_time_agency]
# finally, count all remaining entries
values = all_df_times.loc[:, query]
# get unique entries and counts
counts = len(values) # unique, counts = np.unique(values, return_counts=True)
return counts # (values, unique, counts)

View File

@ -15,7 +15,7 @@ def GetBerths(token):
try:
pooledConnection = local_db.getPoolConnection()
commands = pydapper.using(pooledConnection)
data = commands.query("SELECT id, name, participant_id, `lock`, owner_id, authority_id, created, modified, deleted FROM berth WHERE deleted = 0 ORDER BY name", model=model.Berth)
data = commands.query("SELECT id, name, `lock`, owner_id, authority_id, created, modified, deleted FROM berth WHERE deleted = 0 ORDER BY name", model=model.Berth)
pooledConnection.close()
except Exception as ex:

View File

@ -21,8 +21,8 @@ def GetShipcalls(options):
commands = pydapper.using(pooledConnection)
query = ("SELECT id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, "
"flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, "
"anchored, moored_lock, canceled, evaluation, evaluation_message, created, modified FROM shipcall WHERE ((type = 1 OR type = 2) AND eta >= DATE(NOW() - INTERVAL %d DAY)"
"OR (type = 3 AND etd >= DATE(NOW() - INTERVAL %d DAY))) "
"anchored, moored_lock, canceled, evaluation, evaluation_message, created, modified FROM shipcall WHERE ((type = 1 OR type = 3) AND eta >= DATE(NOW() - INTERVAL %d DAY)"
"OR (type = 2 AND etd >= DATE(NOW() - INTERVAL %d DAY))) "
"ORDER BY eta") % (options["past_days"], options["past_days"])
data = commands.query(query, model=model.Shipcall)

View File

@ -10,7 +10,7 @@ def initPool(instancePath):
try:
global config_path
if(config_path == None):
config_path = os.path.join(instancePath,'../../../secure/connection_data_test.json');
config_path = os.path.join(instancePath,'../../../secure/connection_data_prod.json');
print (config_path)

View File

@ -16,7 +16,6 @@ def obj_dict(obj):
class Berth(Schema):
id: int
name: str
participant_id: int
lock: bool
owner_id: int
authority_id: int

View File

@ -3,3 +3,4 @@ def generate_uuid1_int():
"""# TODO: clarify, what kind of integer ID is used in mysql. Generates a proxy ID, which is used in the stubs"""
from uuid import uuid1
return uuid1().int>>64

View File

@ -7,7 +7,6 @@ def get_berth_simple():
# Note: #TODO: name, participant_id & lock state are arbitrary
name = "Avangard Dalben"
participant_id = 1# e.g., Avangard
lock = False
owner_id = 1 # e.g., Avangard
authority_id = 1 # e.g., Avangard
@ -19,7 +18,6 @@ def get_berth_simple():
berth = Berth(
berth_id,
name,
participant_id,
lock,
owner_id,
authority_id,

View File

@ -0,0 +1,78 @@
import pandas as pd
import random
import datetime
from BreCal.stubs.times_agency import get_times_agency
from BreCal.stubs.times_bsmd import get_times_bsmd
from BreCal.stubs.times_mooring import get_times_mooring
from BreCal.stubs.times_pilot import get_times_pilot
from BreCal.stubs.times_portauthority import get_times_port_authority
from BreCal.stubs.times_terminal import get_times_terminal
from BreCal.stubs.times_tug import get_times_tug
from BreCal.database.enums import ParticipantType
def get_df_times(shipcall=None):
"""in case of providing a shipcall, one can read the id to set each times entry in the dataframe towards that shipcall id"""
df_times = pd.DataFrame([
fct()
for fct in [
get_times_agency,
get_times_bsmd,
get_times_mooring,
get_times_pilot,
get_times_port_authority,
get_times_terminal,
get_times_tug
]
])
if shipcall is not None:
df_times.loc[:,"shipcall_id"] = shipcall.id
return df_times
def random_time_perturbation(df_times, query):
# random perturbations
population = [datetime.datetime.now(), None, pd.NaT]
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, query] = random.sample(population,k=1)[0]
df_times.loc[df_times["participant_type"]==ParticipantType.MOORING.value, query] = random.sample(population,k=1)[0]
df_times.loc[df_times["participant_type"]==ParticipantType.PORT_ADMINISTRATION.value, query] = random.sample(population,k=1)[0]
df_times.loc[df_times["participant_type"]==ParticipantType.PILOT.value, query] = random.sample(population,k=1)[0]
df_times.loc[df_times["participant_type"]==ParticipantType.TUG.value, query] = random.sample(population,k=1)[0]
return df_times
def get_df_times_participants_disagree(query, shipcall=None, df_times = None):
if df_times is None:
df_times = get_df_times(shipcall)
df_times = random_time_perturbation(df_times=df_times, query=query)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, query] = datetime.datetime.now()+datetime.timedelta(hours=2, minutes=14)
df_times.loc[df_times["participant_type"]==ParticipantType.PILOT.value, query] = datetime.datetime.now()+datetime.timedelta(hours=1, minutes=7)
return df_times
def build_stub_df_times(shipcall, query, reference_time):
"""creates an artificial dataset, which simulates having too many shipcalls with too many identical times"""
df_times_a = get_df_times(shipcall)
df_times_a = df_times_a.loc[df_times_a["participant_type"]==ParticipantType.AGENCY.value]
df_times_a.loc[:,query] = reference_time + datetime.timedelta(seconds=17)
df_times_b = get_df_times(shipcall)
df_times_b = df_times_b.loc[df_times_b["participant_type"]==ParticipantType.AGENCY.value]
df_times_b.loc[:,query] = reference_time + datetime.timedelta(seconds=21)
df_times_c = get_df_times(shipcall)
df_times_c = df_times_c.loc[df_times_c["participant_type"]==ParticipantType.AGENCY.value]
df_times_c.loc[:,query] = reference_time + datetime.timedelta(seconds=26)
df_times_d = get_df_times(shipcall)
df_times_d = df_times_d.loc[df_times_d["participant_type"]==ParticipantType.AGENCY.value]
df_times_d.loc[:,query] = reference_time + datetime.timedelta(seconds=28)
df_times_e = get_df_times(shipcall)
df_times_e = df_times_e.loc[df_times_e["participant_type"]==ParticipantType.AGENCY.value]
df_times_e.loc[:,query] = reference_time + datetime.timedelta(seconds=29)
return pd.concat([df_times_a, df_times_b, df_times_c, df_times_d, df_times_e],axis=0)

View File

@ -0,0 +1,8 @@
from BreCal.stubs.times_full import get_times_full_simple
from BreCal.database.enums import ParticipantType
def get_times_agency():
times_agency = get_times_full_simple()
times_agency.participant_type = ParticipantType.AGENCY.value
return times_agency

View File

@ -0,0 +1,8 @@
from BreCal.stubs.times_full import get_times_full_simple
from BreCal.database.enums import ParticipantType
def get_times_bsmd():
times_bsmd = get_times_full_simple()
times_bsmd.participant_type = ParticipantType.BSMD.value
return times_bsmd

View File

@ -3,9 +3,11 @@ this stub creates an example time object, where the times of every role are pres
users will thereby be able to modify these values
"""
import datetime
from BreCal.stubs import generate_uuid1_int
from BreCal.schemas.model import Times
def get_times_full_simple():
# only used for the stub
base_time = datetime.datetime.now()
@ -65,3 +67,5 @@ def get_times_full_simple():
modified=modified,
)
return times

View File

@ -0,0 +1,8 @@
from BreCal.stubs.times_full import get_times_full_simple
from BreCal.database.enums import ParticipantType
def get_times_mooring():
times_mooring = get_times_full_simple()
times_mooring.participant_type = ParticipantType.MOORING.value
return times_mooring

View File

@ -0,0 +1,8 @@
from BreCal.stubs.times_full import get_times_full_simple
from BreCal.database.enums import ParticipantType
def get_times_pilot():
times_pilot = get_times_full_simple()
times_pilot.participant_type = ParticipantType.PILOT.value
return times_pilot

View File

@ -0,0 +1,9 @@
from BreCal.stubs.times_full import get_times_full_simple
from BreCal.database.enums import ParticipantType
def get_times_port_authority():
times_port_authority = get_times_full_simple()
times_port_authority.participant_type = ParticipantType.PORT_ADMINISTRATION.value
return times_port_authority

View File

@ -0,0 +1,8 @@
from BreCal.stubs.times_full import get_times_full_simple
from BreCal.database.enums import ParticipantType
def get_times_terminal():
times_terminal = get_times_full_simple()
times_terminal.participant_type = ParticipantType.TERMINAL.value
return times_terminal

View File

@ -0,0 +1,8 @@
from BreCal.stubs.times_full import get_times_full_simple
from BreCal.database.enums import ParticipantType
def get_times_tug():
times_tug = get_times_full_simple()
times_tug.participant_type = ParticipantType.TUG.value
return times_tug

View File

@ -7,6 +7,43 @@ from BreCal.validators.time_logic import TimeLogic
from BreCal.database.enums import StatusFlags
#from BreCal.validators.schema_validation import validation_state_and_validation_name
# a human interpretable dictionary for error messages. In this case, the English language is preferred
error_message_dict = {
# 0001 A-M
"validation_rule_fct_missing_time_agency_berth_eta":"The shipcall arrives in less than 20 hours, but there are still missing times by the agency. Please add the estimated time of arrival (ETA) {Rule #0001A}", # A
"validation_rule_fct_missing_time_agency_berth_etd":"The shipcall departs in less than 20 hours, but there are still missing times by the agency. Please add the estimated time of departure (ETD) {Rule #0001B}", # B
"validation_rule_fct_missing_time_mooring_berth_eta":"The shipcall arrives in less than 16 hours, but there are still missing times by the mooring. Please add the estimated time of arrival (ETA) {Rule #0001C}", # C
"validation_rule_fct_missing_time_mooring_berth_etd":"The shipcall departs in less than 16 hours, but there are still missing times by the mooring. Please add the estimated time of departure (ETD) {Rule #0001D}", # D
"validation_rule_fct_missing_time_portadministration_berth_eta":"The shipcall arrives in less than 16 hours, but there are still missing times by the port administration. Please add the estimated time of arrival (ETA) {Rule #0001F}", # F
"validation_rule_fct_missing_time_portadministration_berth_etd":"The shipcall departs in less than 16 hours, but there are still missing times by the port administration. Please add the estimated time of departure (ETD) {Rule #0001G}", # G
"validation_rule_fct_missing_time_pilot_berth_eta":"The shipcall arrives in less than 16 hours, but there are still missing times by the pilot. Please add the estimated time of arrival (ETA) {Rule #0001H}", # H
"validation_rule_fct_missing_time_pilot_berth_etd":"The shipcall departs in less than 16 hours, but there are still missing times by the pilot. Please add the estimated time of departure (ETD) {Rule #0001I}", # I
"validation_rule_fct_missing_time_tug_berth_eta":"The shipcall arrives in less than 16 hours, but there are still missing times by the tugs. Please add the estimated time of arrival (ETA) {Rule #0001J}", # J
"validation_rule_fct_missing_time_tug_berth_etd":"The shipcall departs in less than 16 hours, but there are still missing times by the tugs. Please add the estimated time of departure (ETD) {Rule #0001K}", # K
"validation_rule_fct_missing_time_terminal_berth_eta":"The shipcall arrives in less than 16 hours, but there are still missing times by the terminal. Please add the estimated time of arrival (ETA) {Rule #0001L}", # L
"validation_rule_fct_missing_time_terminal_berth_etd":"The shipcall departs in less than 16 hours, but there are still missing times by the terminal. Please add the estimated time of departure (ETD) {Rule #0001M}", # M
# 0002 A+B+C
"validation_rule_fct_shipcall_incoming_participants_disagree_on_eta":"There are deviating times between agency, mooring, port authority, pilot and tug for the estimated time of arrival (ETA) {Rule #0002A}",
"validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd":"There are deviating times between agency, mooring, port authority, pilot and tug for the estimated time of departure (ETD) {Rule #0002B}",
"validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd":"There are deviating times between agency, mooring, port authority, pilot and tug for ETA and ETD {Rule #0002C}",
# 0003 A+B
"validation_rule_fct_eta_time_not_in_operation_window":"The estimated time of arrival will be AFTER the planned start of operations. {Rule #0003A}",
"validation_rule_fct_etd_time_not_in_operation_window":"The estimated time of departure is supposed to be AFTER the planned end of operations. {Rule #0003D}",
# 0004 A+B
"validation_rule_fct_eta_time_not_in_tidal_window":"The tidal window does not fit to the agency's estimated time of arrival (ETA) {Rule #0004A}",
"validation_rule_fct_etd_time_not_in_tidal_window":"The tidal window does not fit to the agency's estimated time of departure (ETD) {Rule #0004B}",
# 0005 A+B
"validation_rule_fct_too_many_identical_eta_times":"There are more than three ships with the same planned time of arrival (ETA) {Rule #0005A}",
"validation_rule_fct_too_many_identical_etd_times":"There are more than three ships with the same planned time of departure (ETD) {Rule #0005B}",
# 0006 A+B
"validation_rule_fct_agency_and_terminal_berth_id_disagreement":"Agency and Terminal are planning with different berths (the berth_id deviates). {Rule #0006A}",
"validation_rule_fct_agency_and_terminal_pier_side_disagreement":"Agency and Terminal are planning with different pier sides (the pier_side deviates). {Rule #0006B}",
}
class ValidationRuleBaseFunctions():
"""
@ -16,6 +53,16 @@ class ValidationRuleBaseFunctions():
def __init__(self, sql_handler):
self.sql_handler = sql_handler
self.time_logic = TimeLogic()
self.error_message_dict = error_message_dict
def describe_error_message(self, key)->str:
"""
Takes any error message, which typically is the validation rule's function name and returns a description of the error.
In case that the error code is not defined in self.error_message_dict, return the cryptic error code instead
returns: string
"""
return self.error_message_dict.get(key,key)
def check_time_delta_violation_query_time_to_now(self, query_time:pd.Timestamp, key_time:pd.Timestamp, threshold:float)->bool:
"""
@ -26,17 +73,22 @@ class ValidationRuleBaseFunctions():
when the query_time lays in the future, the delta is positive
returns a violation state depending on whether the delta is
Violation, if: 0 >= delta > threshold
Violation, if: 0 >= delta <= threshold
When the key time is defined (not None), there is no violation. Returns False
options:
query_time: will be used to measure the time difference of 'now' until the query time
key_time: will be used to check, whether the respective key already has a value
threshold: threshold where a time difference becomes crucial. When the delta is below the threshold, a violation might occur
threshold: threshold where a time difference becomes crucial. When the delta is below the threshold, a violation might occur (minutes)
"""
# rule is not applicable -> return 'GREEN'
if key_time is not None:
# rule is only applicable, when 'key_time' is not defined (neither None, nor pd.NaT)
if (key_time is not None) and (key_time is not pd.NaT):
return False
# when query_time is not valid, the rule cannot be applied
if self.check_is_not_a_time_or_is_none(query_time):
return False
# otherwise, this rule applies and the difference between 'now' and the query time is measured
@ -44,7 +96,7 @@ class ValidationRuleBaseFunctions():
# a violation occurs, when the delta (in minutes) exceeds the specified threshold of a participant
# to prevent past-events from triggering violations, negative values are ignored
# Violation, if 0 >= delta >= threshold
# Violation, if 0 <= delta <= threshold
violation_state = (delta >= 0) and (delta<=threshold)
return violation_state
@ -76,7 +128,7 @@ class ValidationRuleBaseFunctions():
df_times = df_times.loc[df_times["participant_type"].isin(participant_types),:]
# exclude missing entries and consider only pd.Timestamp entries (which ignores pd.NaT/null entries)
estimated_times = [type(time_) for time_ in df_times.loc[:,query].tolist() if isinstance(time_, pd.Timestamp)] # df_times = df_times.loc[~df_times[query].isnull(),:]
estimated_times = [time_ for time_ in df_times.loc[:,query].tolist() if isinstance(time_, pd.Timestamp)] # df_times = df_times.loc[~df_times[query].isnull(),:]
# apply rounding. For example, the agreement of different participants may be required to match minute-wise
# '15min' rounds to 'every 15 minutes'. E.g., '2023-09-22 08:18:49' becomes '2023-09-22 08:15:00'
@ -94,7 +146,7 @@ class ValidationRuleBaseFunctions():
violation_state = n_unique_times!=1
return violation_state
def check_unique_shipcall_counts(self, query:str, rounding="min", maximum_threshold=3)->bool:
def check_unique_shipcall_counts(self, query:str, times_agency:pd.DataFrame, rounding="min", maximum_threshold=3, all_times_agency=None)->bool:
"""
# base function for all validation rules in the group {0005} A&B
@ -103,15 +155,21 @@ class ValidationRuleBaseFunctions():
"""
# filter the df: keep only times_agents
# filter out all NaN and NaT entries
times_agency = self.sql_handler.get_times_for_agency(non_null_column=query)
if all_times_agency is None:
all_times_agency = self.sql_handler.get_times_for_agency(non_null_column=query)
# get values and optionally round the values
(values, unique, counts) = self.sql_handler.get_unique_ship_counts(all_df_times=times_agency, query=query, rounding=rounding, maximum_threshold=maximum_threshold)
# get values and optionally round the values (internally)
counts = self.sql_handler.get_unique_ship_counts(all_df_times=all_times_agency, times_agency=times_agency, query=query, rounding=rounding, maximum_threshold=maximum_threshold)
# when ANY of the unique values exceeds the threshold, a violation is observed
violation_state = np.any(np.greater(counts, maximum_threshold))
return violation_state
def check_is_not_a_time_or_is_none(self, value)->bool:
"""checks, if a provided value is either None or NaT"""
return (value is None) or (value is pd.NaT)
class ValidationRuleFunctions(ValidationRuleBaseFunctions):
"""
@ -466,12 +524,12 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
def validation_rule_fct_missing_time_terminal_berth_etd(self, shipcall, df_times, *args, **kwargs):
"""
Code: #0001-K
Code: #0001-M
Type: Local Rule
Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
a certain threshold (e.g., 20 hours), a violation occurs
0001-K:
0001-M:
- Checks, if times_terminal.etd_berth is filled in.
- Measures the difference between 'now' and 'times_agency.etd_berth'.
"""
@ -595,11 +653,11 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value)
if (times_terminal.operations_end is pd.NaT) or (times_agency.etd_berth is pd.NaT):
if self.check_is_not_a_time_or_is_none(times_terminal.operations_start) or self.check_is_not_a_time_or_is_none(times_agency.eta_berth):
return (StatusFlags.GREEN, None)
# check, whether the start of operations is AFTER the estimated arrival time
violation_state = times_terminal.operations_start<times_agency.eta_berth
violation_state = times_terminal.operations_start < times_agency.eta_berth
if violation_state:
validation_name = inspect.currentframe().f_code.co_name
@ -607,7 +665,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
else:
return (StatusFlags.GREEN, None)
def validation_rule_fct_eta_time_not_in_operation_window(self, shipcall, df_times, *args, **kwargs):
def validation_rule_fct_etd_time_not_in_operation_window(self, shipcall, df_times, *args, **kwargs):
"""
Code: #0003-B
Type: Local Rule
@ -624,7 +682,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value)
if (times_terminal.operations_end is pd.NaT) or (times_agency.etd_berth is pd.NaT):
if self.check_is_not_a_time_or_is_none(times_terminal.operations_end) or self.check_is_not_a_time_or_is_none(times_agency.etd_berth):
return (StatusFlags.GREEN, None)
# check, whether the end of operations is AFTER the estimated departure time
@ -651,11 +709,11 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
# requirements: tidal window (from & to) is filled in
if (shipcall.tidal_window_from is pd.NaT) or (shipcall.tidal_window_to is pd.NaT) or (df_times.eta_berth is pd.NaT):
if self.check_is_not_a_time_or_is_none(shipcall.tidal_window_from) or self.check_is_not_a_time_or_is_none(shipcall.tidal_window_to) or self.check_is_not_a_time_or_is_none(times_agency.eta_berth): # 202310310: note: this should check times_agency, shouldn't it?
return (StatusFlags.GREEN, None)
# check, whether the query time is between start & end time
# a violation is observed, when the is NOT between start & end
# a violation is observed, when the time is NOT between start & end
violation_state = not self.time_logic.time_inbetween(query_time=times_agency.eta_berth, start_time=shipcall.tidal_window_from, end_time=shipcall.tidal_window_to)
if violation_state:
@ -679,11 +737,11 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
# requirements: tidal window (from & to) is filled in
if (shipcall.tidal_window_from is pd.NaT) or (shipcall.tidal_window_to is pd.NaT) or (df_times.etd_berth is pd.NaT):
if self.check_is_not_a_time_or_is_none(shipcall.tidal_window_from) or self.check_is_not_a_time_or_is_none(shipcall.tidal_window_to) or self.check_is_not_a_time_or_is_none(times_agency.etd_berth): # 202310310: note: this should check times_agency, shouldn't it?
return (StatusFlags.GREEN, None)
# check, whether the query time is between start & end time
# a violation is observed, when the is NOT between start & end
# a violation is observed, when the time is NOT between start & end
violation_state = not self.time_logic.time_inbetween(query_time=times_agency.etd_berth, start_time=shipcall.tidal_window_from, end_time=shipcall.tidal_window_to)
if violation_state:
@ -692,15 +750,20 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
else:
return (StatusFlags.GREEN, None)
def validation_rule_fct_too_many_identical_eta_times(self, shipcall, df_times, rounding = "min", maximum_threshold = 3, *args, **kwargs):
def validation_rule_fct_too_many_identical_eta_times(self, shipcall, df_times, rounding = "min", maximum_threshold = 3, all_times_agency=None, *args, **kwargs):
"""
Code: #0005-A
Type: Global Rule
Description: this validation rule checks, whether there are too many shipcalls with identical ETA times.
"""
times_agency = df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value]
# check, if the header is filled in (agency)
if len(times_agency) != 1:
return (StatusFlags.GREEN, None)
# when ANY of the unique values exceeds the threshold, a violation is observed
query = "eta_berth"
violation_state = self.check_unique_shipcall_counts(query, rounding=rounding, maximum_threshold=maximum_threshold)
violation_state = self.check_unique_shipcall_counts(query, times_agency=times_agency, rounding=rounding, maximum_threshold=maximum_threshold, all_times_agency=all_times_agency)
if violation_state:
validation_name = inspect.currentframe().f_code.co_name
@ -708,15 +771,20 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
else:
return (StatusFlags.GREEN, None)
def validation_rule_fct_too_many_identical_etd_times(self, shipcall, df_times, rounding = "min", maximum_threshold = 3, *args, **kwargs):
def validation_rule_fct_too_many_identical_etd_times(self, shipcall, df_times, rounding = "min", maximum_threshold = 3, all_times_agency=None, *args, **kwargs):
"""
Code: #0005-B
Type: Global Rule
Description: this validation rule checks, whether there are too many shipcalls with identical ETD times.
"""
times_agency = df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value]
# check, if the header is filled in (agency)
if len(times_agency) != 1:
return (StatusFlags.GREEN, None)
# when ANY of the unique values exceeds the threshold, a violation is observed
query = "etd_berth"
violation_state = self.check_unique_shipcall_counts(query, rounding=rounding, maximum_threshold=maximum_threshold)
violation_state = self.check_unique_shipcall_counts(query, times_agency=times_agency, rounding=rounding, maximum_threshold=maximum_threshold, all_times_agency=all_times_agency)
if violation_state:
validation_name = inspect.currentframe().f_code.co_name
@ -737,6 +805,18 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value)
# when one of the two values is null, the state is GREEN
if (times_agency.berth_id is None) or (times_terminal.berth_id is None):
return (StatusFlags.GREEN, None)
# when one of the two values is null, the state is GREEN
if (pd.isnull(times_agency.berth_id)) or (pd.isnull(times_terminal.berth_id)):
return (StatusFlags.GREEN, None)
if shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return (StatusFlags.GREEN, None)
# only incoming shipcalls matter. The other ones are not relevant for the berth selection
violation_state = times_agency.berth_id!=times_terminal.berth_id
if violation_state:
@ -758,6 +838,18 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value)
# when one of the two values is null, the state is GREEN
if (times_agency.pier_side is None) or (times_terminal.pier_side is None):
return (StatusFlags.GREEN, None)
# when one of the two values is null, the state is GREEN
if (pd.isnull(times_agency.pier_side)) or (pd.isnull(times_terminal.pier_side)):
return (StatusFlags.GREEN, None)
# only incoming shipcalls matter. The other ones are not relevant for the pier_side selection
if shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return (StatusFlags.GREEN, None)
violation_state = times_agency.pier_side!=times_terminal.pier_side
if violation_state:

View File

@ -41,6 +41,9 @@ class ValidationRules(ValidationRuleFunctions):
# filter out all 'None' results, which indicate that no violation occured.
evaluation_results = [evaluation_result for evaluation_result in evaluation_results if evaluation_result[1] is not None]
# 'translate' all error codes into readable, human-understandable format.
evaluation_results = [(state, self.describe_error_message(msg)) for (state, msg) in evaluation_results]
""" # deprecated
# check, if ANY of the evaluation results (evaluation_state) is larger than the .GREEN state. This means, that .YELLOW and .RED
# would return 'True'. Numpy arrays and functions are used to accelerate the comparison.

View File

@ -2,7 +2,7 @@ import os
import sys
import logging
sys.path.insert(0, '/var/www/brecal_test/src/server')
sys.path.insert(0, '/var/www/brecal/src/server')
sys.path.insert(0, '/var/www/venv/lib/python3.10/site-packages/')
# set the key

View File

@ -44,7 +44,7 @@ def test_import_webargs():
from webargs.flaskparser import parser
return
def test_import_mashmallow():
def test_import_marshmallow():
"""currently used in ~/brecal/src/server/BreCal/api/shipcalls.py"""
import marshmallow
from marshmallow import Schema, fields

View File

@ -1,7 +1,13 @@
import pytest
import datetime
import pandas as pd
from BreCal.validators.validation_rule_functions import ValidationRuleFunctions
from BreCal.validators.validation_rules import ValidationRules
from BreCal.database.sql_handler import SQLHandler
from BreCal.database.enums import ParticipantwiseTimeDelta, ParticipantType, StatusFlags, ShipcallType
from BreCal.stubs.shipcall import get_shipcall_simple
from BreCal.stubs.df_times import get_df_times, random_time_perturbation, get_df_times_participants_disagree, build_stub_df_times
@pytest.fixture(scope="session")
def build_sql_proxy_connection():
@ -25,38 +31,796 @@ def test_build_validation_rule_functions(build_sql_proxy_connection):
def test_validation_rule_fct_agency_and_terminal_pier_side_disagreement(build_sql_proxy_connection):
"""#0006-A validation_rule_fct_agency_and_terminal_pier_side_disagreement"""
import pandas as pd
from BreCal.stubs.times_full import get_times_full_simple
from BreCal.stubs.shipcall import get_shipcall_simple
from BreCal.database.enums import ParticipantType
from BreCal.database.enums import StatusFlags
def test_check_time_delta_violation_query_time_to_now_key_time_is_defined(build_sql_proxy_connection):
vr = build_sql_proxy_connection["vr"]
shipcall = get_shipcall_simple()
t1 = get_times_full_simple()
t2 = get_times_full_simple()
# roles: agency & terminal
t1.participant_type = ParticipantType.AGENCY.value
t2.participant_type = ParticipantType.TERMINAL.value
# ship arrives in three hours, while the threshold for an alert is (e.g.) 5 hours
# key time is given, so the function should always return False (no violation)
query_time = datetime.datetime.now() + datetime.timedelta(hours=3)
key_time = datetime.datetime.now() + datetime.timedelta(hours=7, minutes=30)
# disagreement
t1.pier_side = True
t2.pier_side = False
time_objects = [t1, t2]
df_times = pd.DataFrame.from_records([to_.__dict__ for to_ in time_objects])
df_times.set_index('id',inplace=True)
(state, description) = vr.validation_rule_fct_agency_and_terminal_pier_side_disagreement(shipcall, df_times)
assert state.value > StatusFlags.GREEN.value, f"a violation must be identified"
assert description is not None, f"a violation description must be identified"
threshold = 60*5
violation_state = vr.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
assert not violation_state, f"the key time is filled in, so there should not be a violation"
return
def test_check_time_delta_violation_query_time_to_now_no_key_time_but_event_in_distant_future(build_sql_proxy_connection):
vr = build_sql_proxy_connection["vr"]
# ship arrives in three hours, while the threshold for an alert is (e.g.) 5 hours
# key time is given, so the function should always return False (no violation)
# query time (-> delta) & threshold have the same time -> no violation
query_time = datetime.datetime.now() + datetime.timedelta(hours=5, seconds=10) # when the delta & threshold are identical, microseconds between checking the time and defining it here, raise the violation
key_time = None
threshold = 60*5
violation_state = vr.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
assert not violation_state, f"the event is still far enough away, so there should not be a violation."
return
def test_check_time_delta_violation_query_time_to_now_key_time_is_none(build_sql_proxy_connection):
vr = build_sql_proxy_connection["vr"]
# ship arrives in three hours, while the threshold for an alert is (e.g.) 5 hours
# key time is given, so the function should always return False (no violation)
query_time = datetime.datetime.now() + datetime.timedelta(hours=3)
key_time = None
threshold = 60*5 # minutes
violation_state = vr.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
assert violation_state, f"when the key time is not filled in and the query time is 'dangerously close', there should be a violation to indicate the traffic state"
return
def test_check_time_delta_violation_query_time_to_now_key_time_is_pd_nat(build_sql_proxy_connection):
vr = build_sql_proxy_connection["vr"]
# ship arrives in three hours, while the threshold for an alert is (e.g.) 5 hours
# key time is given, so the function should always return False (no violation)
query_time = datetime.datetime.now() + datetime.timedelta(hours=3)
key_time = pd.NaT
threshold = 60*5 # minutes
violation_state = vr.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
assert violation_state, f"when the key time is not filled in and the query time is 'dangerously close', there should be a violation to indicate the traffic state"
return
def test_validation_rule_fct_missing_time_agency_berth_eta__missing_time_agency_no_violation(build_sql_proxy_connection):
"""0001-A validation_rule_fct_missing_time_agency_berth_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# artificially remove the agency, so the function is properly checked
df_times = df_times.loc[df_times["participant_type"]!=ParticipantType.AGENCY.value]
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_agency_berth_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.GREEN, f"function should return 'green', because the agency's entry is not present"
assert msg is None, f"with a 'green' state, there should be no message returned"
return
def test_validation_rule_fct_missing_time_agency_berth_eta__shipcall_eta_dangerously_close_no_times_agency(build_sql_proxy_connection):
"""0001-A validation_rule_fct_missing_time_agency_berth_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# the shipcall happens 'soon'
shipcall.eta = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.AGENCY-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_agency_berth_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the agency's entry is not present and the shipcall takes place soon"
return
def test_validation_rule_fct_missing_time_agency_berth_eta__shipcall_eta_distant_enough_no_times_agency(build_sql_proxy_connection):
"""0001-A validation_rule_fct_missing_time_agency_berth_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# the shipcall happens 'soon'
shipcall.eta = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.AGENCY+10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_agency_berth_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.GREEN, f"function should return 'yellow', because the agency's entry is not present and the shipcall takes place soon"
return
def test_validation_rule_fct_missing_time_agency_berth_eta__shipcall_eta_is_undefined_agency_eta_is_defined(build_sql_proxy_connection):
"""0001-A validation_rule_fct_missing_time_agency_berth_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# the shipcall is undefined
shipcall.eta = None
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_agency_berth_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.GREEN, f"function should return 'yellow', because the agency's entry is not present and the shipcall takes place soon"
return
def test_validation_rule_fct_missing_time_agency_berth_etd__shipcall_etd_is_undefined_agency_etd_is_defined(build_sql_proxy_connection):
"""0001-B validation_rule_fct_missing_time_agency_berth_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# the shipcall etd is 'soon'
shipcall.etd = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.AGENCY-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_agency_berth_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the agency's entry is not present and the shipcall takes place soon"
return
def test_validation_rule_fct_missing_time_mooring_berth_eta__shipcall_soon_but_participant_estimated_time_undefined(build_sql_proxy_connection):
"""0001-C validation_rule_fct_missing_time_mooring_berth_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# according to the agency, a shipcall takes place soon (ETA/ETD)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.MOORING-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.MOORING.value, "eta_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_mooring_berth_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the participant did not provide a time and the shipcall takes place soon (according to the agency)"
return
def test_validation_rule_fct_missing_time_mooring_berth_etd__shipcall_soon_but_participant_estimated_time_undefined(build_sql_proxy_connection):
"""0001-D validation_rule_fct_missing_time_mooring_berth_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# according to the agency, a shipcall takes place soon (ETA/ETD)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.MOORING-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.MOORING.value, "etd_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_mooring_berth_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the participant did not provide a time and the shipcall takes place soon (according to the agency)"
return
def test_validation_rule_fct_missing_time_portadministration_berth_eta__shipcall_soon_but_participant_estimated_time_undefined(build_sql_proxy_connection):
"""0001-F validation_rule_fct_missing_time_portadministration_berth_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# according to the agency, a shipcall takes place soon (ETA/ETD)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.PORT_ADMINISTRATION-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.PORT_ADMINISTRATION.value, "eta_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_portadministration_berth_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the participant did not provide a time and the shipcall takes place soon (according to the agency)"
return
def test_validation_rule_fct_missing_time_portadministration_berth_etd__shipcall_soon_but_participant_estimated_time_undefined(build_sql_proxy_connection):
"""0001-G validation_rule_fct_missing_time_portadministration_berth_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# according to the agency, a shipcall takes place soon (ETA/ETD)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.PORT_ADMINISTRATION-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.PORT_ADMINISTRATION.value, "etd_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_portadministration_berth_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the participant did not provide a time and the shipcall takes place soon (according to the agency)"
return
def test_validation_rule_fct_missing_time_pilot_berth_eta__shipcall_soon_but_participant_estimated_time_undefined(build_sql_proxy_connection):
"""0001-H validation_rule_fct_missing_time_pilot_berth_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# according to the agency, a shipcall takes place soon (ETA/ETD)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.PILOT-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.PILOT.value, "eta_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_pilot_berth_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the participant did not provide a time and the shipcall takes place soon (according to the agency)"
return
def test_validation_rule_fct_missing_time_pilot_berth_etd__shipcall_soon_but_participant_estimated_time_undefined(build_sql_proxy_connection):
"""0001-I validation_rule_fct_missing_time_pilot_berth_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# according to the agency, a shipcall takes place soon (ETA/ETD)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.PILOT-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.PILOT.value, "etd_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_pilot_berth_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the participant did not provide a time and the shipcall takes place soon (according to the agency)"
return
def test_validation_rule_fct_missing_time_tug_berth_eta__shipcall_soon_but_participant_estimated_time_undefined(build_sql_proxy_connection):
"""0001-J validation_rule_fct_missing_time_tug_berth_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# according to the agency, a shipcall takes place soon (ETA/ETD)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.TUG-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.TUG.value, "eta_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_tug_berth_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the participant did not provide a time and the shipcall takes place soon (according to the agency)"
return
def test_validation_rule_fct_missing_time_tug_berth_etd__shipcall_soon_but_participant_estimated_time_undefined(build_sql_proxy_connection):
"""0001-K validation_rule_fct_missing_time_tug_berth_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# according to the agency, a shipcall takes place soon (ETA/ETD)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.TUG-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.TUG.value, "etd_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_tug_berth_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the participant did not provide a time and the shipcall takes place soon (according to the agency)"
return
def test_validation_rule_fct_missing_time_terminal_berth_eta__shipcall_soon_but_participant_estimated_time_undefined(build_sql_proxy_connection):
"""0001-L validation_rule_fct_missing_time_terminal_berth_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# according to the agency, a shipcall takes place soon (ETA/ETD)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.TERMINAL-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value, "eta_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_terminal_berth_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the participant did not provide a time and the shipcall takes place soon (according to the agency)"
return
def test_validation_rule_fct_missing_time_terminal_berth_etd__shipcall_soon_but_participant_estimated_time_undefined(build_sql_proxy_connection):
"""0001-M validation_rule_fct_missing_time_terminal_berth_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
# according to the agency, a shipcall takes place soon (ETA/ETD)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = datetime.datetime.now() + datetime.timedelta(minutes=ParticipantwiseTimeDelta.TERMINAL-10)
# set times agency to be undetermined
df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value, "etd_berth"] = None
# apply the validation rule
(state, msg) = vr.validation_rule_fct_missing_time_terminal_berth_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.YELLOW, f"function should return 'yellow', because the participant did not provide a time and the shipcall takes place soon (according to the agency)"
return
def test_validation_rule_fct_shipcall_incoming_participants_disagree_on_eta__participants_disagree_on_time_but_different_shipcall_type(build_sql_proxy_connection):
"""0002-A validation_rule_fct_shipcall_incoming_participants_disagree_on_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
# set shipcall type to NOT match the function -> returns 'green'
query = "eta_berth"
shipcall.type = ShipcallType.SHIFTING.value
df_times = get_df_times_participants_disagree(query=query, shipcall=shipcall)
# apply the validation rule
(state, msg) = vr.validation_rule_fct_shipcall_incoming_participants_disagree_on_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.GREEN, f"function should return 'green', because the shipcall type does not match the function"
return
def test_validation_rule_fct_shipcall_incoming_participants_disagree_on_eta__participants_disagree_on_time(build_sql_proxy_connection):
"""0002-A validation_rule_fct_shipcall_incoming_participants_disagree_on_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
# set shipcall type to match the function
query = "eta_berth"
shipcall.type = ShipcallType.INCOMING.value
df_times = get_df_times_participants_disagree(query=query, shipcall=shipcall) # makes sure that there is disagreement among participants
# apply the validation rule
(state, msg) = vr.validation_rule_fct_shipcall_incoming_participants_disagree_on_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.RED, f"function should return 'red', because agency and pilot disagree on the query"
return
def test_validation_rule_fct_shipcall_incoming_participants_disagree_on_eta__participants_agree_on_time(build_sql_proxy_connection):
"""0002-A validation_rule_fct_shipcall_incoming_participants_disagree_on_eta"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
# set shipcall type to NOT match the function -> returns 'green'
query = "eta_berth"
shipcall.type = ShipcallType.INCOMING.value
df_times = get_df_times(shipcall)
df_times.loc[:,query] = datetime.datetime.now()
# apply the validation rule
(state, msg) = vr.validation_rule_fct_shipcall_incoming_participants_disagree_on_eta(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.GREEN, f"function should return 'green', because the participants fully agree on the time"
return
def test_validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd__participants_disagree_on_time_but_different_shipcall_type(build_sql_proxy_connection):
"""0002-B validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
# set shipcall type to NOT match the function -> returns 'green'
query = "etd_berth"
shipcall.type = ShipcallType.SHIFTING.value
df_times = get_df_times_participants_disagree(query=query, shipcall=shipcall)
# apply the validation rule
(state, msg) = vr.validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.GREEN, f"function should return 'green', because the shipcall type does not match the function"
return
def test_validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd__participants_disagree_on_time(build_sql_proxy_connection):
"""0002-B validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
# set shipcall type to match the function
query = "etd_berth"
shipcall.type = ShipcallType.OUTGOING.value
df_times = get_df_times_participants_disagree(query=query, shipcall=shipcall) # makes sure that there is disagreement among participants
# apply the validation rule
(state, msg) = vr.validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.RED, f"function should return 'red', because agency and pilot disagree on the query"
return
def test_validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd__participants_agree_on_time(build_sql_proxy_connection):
"""0002-B validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
# set shipcall type to NOT match the function -> returns 'green'
query = "etd_berth"
shipcall.type = ShipcallType.OUTGOING.value
df_times = get_df_times(shipcall)
df_times.loc[:,query] = datetime.datetime.now()
# apply the validation rule
(state, msg) = vr.validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.GREEN, f"function should return 'green', because the participants fully agree on the time"
return
def test_validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd__participants_disagree_on_time_but_different_shipcall_type(build_sql_proxy_connection):
"""0002-C validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
shipcall.type = ShipcallType.INCOMING.value
df_times = get_df_times(shipcall)
# set shipcall type to match the function
query = "eta_berth"
df_times = get_df_times_participants_disagree(query=query, shipcall=shipcall, df_times=df_times) # makes sure that there is disagreement among participants
# set shipcall type to match the function
query = "etd_berth"
df_times = get_df_times_participants_disagree(query=query, shipcall=shipcall, df_times=df_times) # makes sure that there is disagreement among participants
# apply the validation rule
(state, msg) = vr.validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.GREEN, f"function should return 'green', because the shipcall type does not match the function"
return
def test_validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd__participants_disagree_on_time(build_sql_proxy_connection):
"""0002-C validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
shipcall.type = ShipcallType.SHIFTING.value
df_times = get_df_times(shipcall)
# set shipcall type to match the function
query = "eta_berth"
df_times = get_df_times_participants_disagree(query=query, shipcall=shipcall, df_times=df_times) # makes sure that there is disagreement among participants
# set shipcall type to match the function
query = "etd_berth"
df_times = get_df_times_participants_disagree(query=query, shipcall=shipcall, df_times=df_times) # makes sure that there is disagreement among participants
# apply the validation rule
(state, msg) = vr.validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.RED, f"function should return 'red', because agency and pilot disagree on the query"
return
def test_validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd__participants_agree_on_time(build_sql_proxy_connection):
"""0002-C validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
shipcall.type = ShipcallType.SHIFTING.value
df_times = get_df_times(shipcall)
# set shipcall type to match the function
query = "eta_berth"
df_times.loc[:,query] = datetime.datetime.now()
# set shipcall type to match the function
query = "etd_berth"
df_times.loc[:,query] = datetime.datetime.now()
# apply the validation rule
(state, msg) = vr.validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd(shipcall=shipcall, df_times=df_times)
# expectation: green state, no msg
assert state==StatusFlags.GREEN, f"function should return 'green', because the participants fully agree on the time"
return
def test_validation_rule_fct_eta_time_not_in_operation_window__times_dont_match(build_sql_proxy_connection):
"""0003-A validation_rule_fct_eta_time_not_in_operation_window"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
t0_time = datetime.datetime.now() # reference time for easier readability
# the planned operations_start is before eta_berth (by one minute in this case)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = t0_time + datetime.timedelta(minutes=1)
df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value, "operations_start"] = t0_time + datetime.timedelta(minutes=0)
(code, msg) = vr.validation_rule_fct_eta_time_not_in_operation_window(shipcall, df_times)
assert code==StatusFlags.RED, f"status flag should be 'red', because the planned operations start is BEFORE the estimated time of arrival for the shipcall"
return
def test_validation_rule_fct_etd_time_not_in_operation_window__times_dont_match(build_sql_proxy_connection):
"""0003-B validation_rule_fct_etd_time_not_in_operation_window"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
t0_time = datetime.datetime.now() # reference time for easier readability
# the planned operations_end is after etd_berth (by one minute in this case)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = t0_time + datetime.timedelta(hours=1)
df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value, "operations_end"] = t0_time+datetime.timedelta(hours=1, minutes=1)
(code, msg) = vr.validation_rule_fct_etd_time_not_in_operation_window(shipcall, df_times)
assert code==StatusFlags.RED, f"status flag should be 'red', because the planned operations end is AFTER the estimated time of departure for the shipcall"
return
def test_validation_rule_fct_eta_time_not_in_operation_window_and_validation_rule_fct_etd_time_not_in_operation_window__always_okay(build_sql_proxy_connection):
"""
0003-A validation_rule_fct_eta_time_not_in_operation_window
0003-B validation_rule_fct_etd_time_not_in_operation_window
"""
vr = build_sql_proxy_connection['vr']
import random
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
t0_time = datetime.datetime.now()
# 10 random permutations of None/pd.NaT/suitable values
# each of these combinations is okay and should return a 'green' state
for _i in range(10):
# eta_berth & operations start
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = random.sample([None, pd.NaT, t0_time + datetime.timedelta(minutes=0)],k=1)[0]
df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value, "operations_start"] = random.sample([None, pd.NaT, t0_time + datetime.timedelta(minutes=0)], k=1)[0]
# etd_berth & operations start
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = random.sample([None, pd.NaT, t0_time + datetime.timedelta(hours=1)],k=1)[0]
df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value, "operations_end"] = random.sample([None, pd.NaT, t0_time+datetime.timedelta(hours=1)],k=1)[0]
(code, msg) = vr.validation_rule_fct_eta_time_not_in_operation_window(shipcall=shipcall, df_times=df_times)
assert code==StatusFlags.GREEN, f"status flag should be 'green', as any of these perturbations sets operation & estimated time to be on par ot one the values missed"
(code, msg) = vr.validation_rule_fct_etd_time_not_in_operation_window(shipcall=shipcall, df_times=df_times)
assert code==StatusFlags.GREEN, f"status flag should be 'green', as any of these perturbations sets operation & estimated time to be on par ot one the values missed"
return
def test_validation_rule_fct_eta_time_not_in_tidal_window__is_okay(build_sql_proxy_connection):
"""0004-A validation_rule_fct_eta_time_not_in_tidal_window"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
t0_time = datetime.datetime.now()
# tidal window: [t0 +1min, t0 +1hr)
# eta berth:
shipcall.tidal_window_from = t0_time + datetime.timedelta(minutes=1)
shipcall.tidal_window_to = t0_time + datetime.timedelta(hours=1)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = t0_time + datetime.timedelta(minutes=1)
(code, msg) = vr.validation_rule_fct_eta_time_not_in_tidal_window(shipcall, df_times)
assert code==StatusFlags.GREEN, f"state should be 'green', because eta_berth matches precisely the tidal_window_from"
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = t0_time + datetime.timedelta(hours=1)
(code, msg) = vr.validation_rule_fct_eta_time_not_in_tidal_window(shipcall, df_times)
assert code==StatusFlags.GREEN, f"state should be 'green', because eta_berth matches precisely the tidal_window_to (in this case, the etd_berth would likely cause an issue)"
return
def test_validation_rule_fct_eta_time_not_in_tidal_window__eta_outside_tidal_window(build_sql_proxy_connection):
"""0004-A validation_rule_fct_eta_time_not_in_tidal_window"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
t0_time = datetime.datetime.now()
# tidal window: [t0 +1min, t0 +1hr)
# eta berth: t0+0min
shipcall.tidal_window_from = t0_time + datetime.timedelta(minutes=1)
shipcall.tidal_window_to = t0_time + datetime.timedelta(hours=1)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = t0_time + datetime.timedelta(minutes=0)
(code, msg) = vr.validation_rule_fct_eta_time_not_in_tidal_window(shipcall, df_times)
assert code==StatusFlags.RED, f"state should be 'red', eta_berth takes place before the tidal window"
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "eta_berth"] = t0_time + datetime.timedelta(hours=1, minutes=1)
(code, msg) = vr.validation_rule_fct_eta_time_not_in_tidal_window(shipcall, df_times)
assert code==StatusFlags.RED, f"state should be 'red', eta_berth takes place after the tidal window"
return
def test_validation_rule_fct_etd_time_not_in_tidal_window__is_okay(build_sql_proxy_connection):
"""0004-B validation_rule_fct_etd_time_not_in_tidal_window"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
t0_time = datetime.datetime.now()
# tidal window: [t0 +1min, t0 +1hr)
# etd berth:
shipcall.tidal_window_from = t0_time + datetime.timedelta(minutes=1)
shipcall.tidal_window_to = t0_time + datetime.timedelta(hours=1)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = t0_time + datetime.timedelta(minutes=1)
(code, msg) = vr.validation_rule_fct_etd_time_not_in_tidal_window(shipcall, df_times)
assert code==StatusFlags.GREEN, f"state should be 'green', because etd_berth matches precisely the tidal_window_from"
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = t0_time + datetime.timedelta(hours=1)
(code, msg) = vr.validation_rule_fct_etd_time_not_in_tidal_window(shipcall, df_times)
assert code==StatusFlags.GREEN, f"state should be 'green', because etd_berth matches precisely the tidal_window_to (in this case, the etd_berth would likely cause an issue)"
return
def test_validation_rule_fct_etd_time_not_in_tidal_window__etd_outside_tidal_window(build_sql_proxy_connection):
"""0004-B validation_rule_fct_etd_time_not_in_tidal_window"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
t0_time = datetime.datetime.now()
# tidal window: [t0 +1min, t0 +1hr)
# etd berth:
shipcall.tidal_window_from = t0_time + datetime.timedelta(minutes=1)
shipcall.tidal_window_to = t0_time + datetime.timedelta(hours=1)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = t0_time + datetime.timedelta(minutes=0)
(code, msg) = vr.validation_rule_fct_etd_time_not_in_tidal_window(shipcall, df_times)
assert code==StatusFlags.RED, f"state should be 'red', etd_berth takes place before the tidal window"
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "etd_berth"] = t0_time + datetime.timedelta(hours=1, minutes=1)
(code, msg) = vr.validation_rule_fct_etd_time_not_in_tidal_window(shipcall, df_times)
assert code==StatusFlags.RED, f"state should be 'red', etd_berth takes place after the tidal window"
return
def test_validation_rule_fct_too_many_identical_eta_times__is_violated_by_too_many_identical_times(build_sql_proxy_connection):
"""0005-A validation_rule_fct_too_many_identical_eta_times"""
vr = build_sql_proxy_connection['vr']
query = "eta_berth"
reference_time = pd.Timestamp(datetime.datetime.now())
reference_time = reference_time.round("min")
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
df_times = df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value]
df_times.loc[:,query] = reference_time + datetime.timedelta(seconds=12)
all_times_df = build_stub_df_times(shipcall, query, reference_time)
(code, msg) = vr.validation_rule_fct_too_many_identical_eta_times(shipcall=shipcall, df_times=df_times, all_times_agency=all_times_df)
assert code == StatusFlags.YELLOW, f"status should be 'yellow', because the artificial 'all_times_df' contains five shipcalls with identical times, which exceeds the threshold"
return
def test_validation_rule_fct_too_many_identical_etd_times__is_violated_by_too_many_identical_times(build_sql_proxy_connection):
"""0005-B validation_rule_fct_too_many_identical_etd_times"""
vr = build_sql_proxy_connection['vr']
query = "etd_berth"
reference_time = pd.Timestamp(datetime.datetime.now())
reference_time = reference_time.round("min")
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
df_times = df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value]
df_times.loc[:,query] = reference_time + datetime.timedelta(seconds=12)
all_times_df = build_stub_df_times(shipcall, query, reference_time)
(code, msg) = vr.validation_rule_fct_too_many_identical_etd_times(shipcall=shipcall, df_times=df_times, all_times_agency=all_times_df)
assert code == StatusFlags.YELLOW, f"status should be 'yellow', because the artificial 'all_times_df' contains five shipcalls with identical times, which exceeds the threshold"
return
def test_validation_rule_fct_agency_and_terminal_berth_id_disagreement__agency_and_terminal_agree(build_sql_proxy_connection):
"""0006-A validation_rule_fct_agency_and_terminal_berth_id_disagreement"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "berth_id"] = 143
df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value, "berth_id"] = 143
(code, msg) = vr.validation_rule_fct_agency_and_terminal_berth_id_disagreement(shipcall=shipcall, df_times=df_times)
assert code==StatusFlags.GREEN, f"status should be 'green', because agency and terminal agree on the selected berth id"
return
def test_validation_rule_fct_agency_and_terminal_berth_id_disagreement__agency_and_terminal_disagree(build_sql_proxy_connection):
"""0006-A validation_rule_fct_agency_and_terminal_berth_id_disagreement"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "berth_id"] = 143
df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value, "berth_id"] = 145
(code, msg) = vr.validation_rule_fct_agency_and_terminal_berth_id_disagreement(shipcall=shipcall, df_times=df_times)
assert code==StatusFlags.YELLOW, f"status should be 'yellow', because agency and terminal do not agree on the selected berth id"
return
def test_validation_rule_fct_agency_and_terminal_pier_side_disagreement__agency_and_terminal_agree(build_sql_proxy_connection):
"""0006-B validation_rule_fct_agency_and_terminal_pier_side_disagreement"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "pier_side"] = True
df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value, "pier_side"] = True
(code, msg) = vr.validation_rule_fct_agency_and_terminal_pier_side_disagreement(shipcall=shipcall, df_times=df_times)
assert code==StatusFlags.GREEN, f"status should be 'green', because agency and terminal agree on the selected pier side"
return
def test_validation_rule_fct_agency_and_terminal_pier_side_disagreement__agency_and_terminal_disagree(build_sql_proxy_connection):
"""0006-B validation_rule_fct_agency_and_terminal_pier_side_disagreement"""
vr = build_sql_proxy_connection['vr']
shipcall = get_shipcall_simple()
df_times = get_df_times(shipcall)
df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value, "pier_side"] = True
df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value, "pier_side"] = False
(code, msg) = vr.validation_rule_fct_agency_and_terminal_pier_side_disagreement(shipcall=shipcall, df_times=df_times)
assert code==StatusFlags.YELLOW, f"status should be 'yellow', because agency and terminal do not agree on the selected pier side"
return
def test_validation_rule_fct_agency_and_terminal_pier_side_agreement(build_sql_proxy_connection):
"""#0006-A validation_rule_fct_agency_and_terminal_pier_side_disagreement"""
@ -89,8 +853,36 @@ def test_validation_rule_fct_agency_and_terminal_pier_side_agreement(build_sql_p
assert description is None, f"no violation should be observed"
return
def test_validation_rule_fct_agency_and_terminal_pier_side_disagreement(build_sql_proxy_connection):
"""#0006-A validation_rule_fct_agency_and_terminal_pier_side_disagreement"""
import pandas as pd
from BreCal.stubs.times_full import get_times_full_simple
from BreCal.stubs.shipcall import get_shipcall_simple
from BreCal.database.enums import ParticipantType
from BreCal.database.enums import StatusFlags
vr = build_sql_proxy_connection["vr"]
shipcall = get_shipcall_simple()
t1 = get_times_full_simple()
t2 = get_times_full_simple()
# roles: agency & terminal
t1.participant_type = ParticipantType.AGENCY.value
t2.participant_type = ParticipantType.TERMINAL.value
# disagreement
t1.pier_side = True
t2.pier_side = False
time_objects = [t1, t2]
df_times = pd.DataFrame.from_records([to_.__dict__ for to_ in time_objects])
df_times.set_index('id',inplace=True)
(state, description) = vr.validation_rule_fct_agency_and_terminal_pier_side_disagreement(shipcall, df_times)
assert state.value > StatusFlags.GREEN.value, f"a violation must be identified"
assert description is not None, f"a violation description must be identified"
return
def test_validation_rule_fct_agency_and_terminal_berth_id_disagreement(build_sql_proxy_connection):
"""#0006-B validation_rule_fct_agency_and_terminal_pier_side_disagreement"""
@ -156,4 +948,12 @@ def test_validation_rule_fct_agency_and_terminal_berth_id_agreement(build_sql_pr
def test_all_validation_rule_fcts_have_a_description():
from BreCal.validators.validation_rule_functions import error_message_dict, ValidationRuleFunctions
import types
vr = ValidationRuleFunctions(sql_handler=None)
assert all(
[mthd_ in list(error_message_dict.keys()) for mthd_ in dir(vr) if ('validation_rule_fct' in mthd_)]
), f"one of the validation_rule_fcts is currently not defined in the error_message_dict and will create cryptic descriptions! Please add it to the error_message_dict BreCal.validators.validation_rule_functions"
return