mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-04-19 11:37:28 +02:00
Version 3.0.381
This commit is contained in:
parent
f963c0a219
commit
3a363acf3a
1525 changed files with 60589 additions and 125098 deletions
|
@ -0,0 +1,129 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BC;
|
||||
using ShareeBike.Model.Bikes;
|
||||
using ShareeBike.Repository.Response;
|
||||
using Serilog;
|
||||
|
||||
namespace ShareeBike.Model.Connector.Updater
|
||||
{
|
||||
public static class BikeCollectionFactory
|
||||
{
|
||||
/// <summary> Gets bikes available from copri server response.</summary>
|
||||
/// <param name="bikesAvailableResponse">Response to create collection from.</param>
|
||||
/// <param name="dataSource">Specified the data source</param>
|
||||
/// <returns>New collection of available bikes.</returns>
|
||||
public static BikeCollection GetBikesAvailable(
|
||||
this BikesAvailableResponse bikesAvailableResponse,
|
||||
DataSource dataSource)
|
||||
=> GetBikesAll(
|
||||
bikesAvailableResponse?.bikes?.Values,
|
||||
bikesAvailableResponse?.bikes_occupied?.Values,
|
||||
string.Empty,
|
||||
() => DateTime.Now,
|
||||
dataSource);
|
||||
|
||||
/// <summary> Gets bikes occupied from copri server response. </summary>
|
||||
/// <param name="bikesOccupiedResponse">Response to create bikes from.</param>
|
||||
/// <param name="dataSource">Specified the data source</param>
|
||||
/// <returns>New collection of occupied bikes.</returns>
|
||||
public static BikeCollection GetBikesOccupied(
|
||||
this BikesReservedOccupiedResponse bikesOccupiedResponse,
|
||||
string mail,
|
||||
Func<DateTime> dateTimeProvider,
|
||||
DataSource dataSource)
|
||||
=> GetBikesAll(
|
||||
new BikesAvailableResponse()?.bikes?.Values,
|
||||
bikesOccupiedResponse?.bikes_occupied?.Values,
|
||||
mail,
|
||||
dateTimeProvider,
|
||||
dataSource);
|
||||
|
||||
/// <summary> Gets bikes occupied from copri server response. </summary>
|
||||
/// <param name="bikesAvailable">Response to create bikes available from.</param>
|
||||
/// <param name="bikesOccupied">Response to create bikes occupied from.</param>
|
||||
/// <returns>New collection of occupied bikes.</returns>
|
||||
public static BikeCollection GetBikesAll(
|
||||
IEnumerable<BikeInfoAvailable> bikesAvailable,
|
||||
IEnumerable<BikeInfoReservedOrBooked> bikesOccupied,
|
||||
string mail,
|
||||
Func<DateTime> dateTimeProvider,
|
||||
DataSource dataSource)
|
||||
{
|
||||
var bikesDictionary = new Dictionary<string, BikeInfo>();
|
||||
var duplicates = new Dictionary<string, BikeInfo>();
|
||||
|
||||
// Get bikes from Copri/ file/ memory, ....
|
||||
if (bikesAvailable != null)
|
||||
{
|
||||
foreach (var bikeInfoResponse in bikesAvailable)
|
||||
{
|
||||
var bikeInfo = BikeInfoFactory.Create(bikeInfoResponse, dataSource);
|
||||
if (bikeInfo == null)
|
||||
{
|
||||
// Response is not valid.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bikesDictionary.ContainsKey(bikeInfo.Id))
|
||||
{
|
||||
// Duplicates are not allowed.
|
||||
Log.Error($"Duplicate bike with id {bikeInfo.Id} detected evaluating bikes available. Bike status is {bikeInfo.State.Value}.");
|
||||
|
||||
if (!duplicates.ContainsKey(bikeInfo.Id))
|
||||
{
|
||||
duplicates.Add(bikeInfo.Id, bikeInfo);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
bikesDictionary.Add(bikeInfo.Id, bikeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// Get bikes from Copri/ file/ memory, ....
|
||||
if (bikesOccupied != null)
|
||||
{
|
||||
foreach (var bikeInfoResponse in bikesOccupied)
|
||||
{
|
||||
BikeInfo bikeInfo = BikeInfoFactory.Create(
|
||||
bikeInfoResponse,
|
||||
mail,
|
||||
dateTimeProvider,
|
||||
dataSource);
|
||||
|
||||
if (bikeInfo == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bikesDictionary.ContainsKey(bikeInfo.Id))
|
||||
{
|
||||
// Duplicates are not allowed.
|
||||
Log.Error($"Duplicate bike with id {bikeInfo.Id} detected evaluating bikes occupied. Bike status is {bikeInfo.State.Value}.");
|
||||
if (!duplicates.ContainsKey(bikeInfo.Id))
|
||||
{
|
||||
duplicates.Add(bikeInfo.Id, bikeInfo);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
bikesDictionary.Add(bikeInfo.Id, bikeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove entries which are not unique.
|
||||
foreach (var l_oDuplicate in duplicates)
|
||||
{
|
||||
bikesDictionary.Remove(l_oDuplicate.Key);
|
||||
}
|
||||
|
||||
return new BikeCollection(bikesDictionary);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
303
SharedBusinessLogic/Model/Connector/Updater/BikeInfoFactory.cs
Normal file
303
SharedBusinessLogic/Model/Connector/Updater/BikeInfoFactory.cs
Normal file
|
@ -0,0 +1,303 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Serilog;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BC;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
|
||||
using ShareeBike.Model.MiniSurvey;
|
||||
using ShareeBike.Model.State;
|
||||
using ShareeBike.Repository.Response;
|
||||
using BikeExtension = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.BikeExtension;
|
||||
|
||||
namespace ShareeBike.Model.Connector.Updater
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs bike info instances/ bike info derived instances.
|
||||
/// </summary>
|
||||
public static class BikeInfoFactory
|
||||
{
|
||||
/// <summary> Set default lock type to . </summary>
|
||||
public static LockModel DEFAULTLOCKMODEL = LockModel.Sigo;
|
||||
|
||||
/// <summary> Creates a bike info object from copri response. </summary>
|
||||
/// <param name="bikeInfo">Copri response for a disposable bike. </param>
|
||||
/// <param name="dataSource">Specifies the data source.</param>
|
||||
public static BikeInfo Create(
|
||||
BikeInfoAvailable bikeInfo,
|
||||
DataSource dataSource)
|
||||
{
|
||||
if (bikeInfo == null) throw new ArgumentNullException(nameof(bikeInfo));
|
||||
|
||||
var lockModel = bikeInfo.GetLockModel();
|
||||
|
||||
if (lockModel.HasValue
|
||||
&& lockModel.Value == LockModel.BordComputer)
|
||||
{
|
||||
// Manual lock bikes are no more supported.
|
||||
Log.Error(
|
||||
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
|
||||
"Manual lock bikes are no more supported." +
|
||||
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $"station number {bikeInfo.station}" : string.Empty)}."
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (bikeInfo.GetState())
|
||||
{
|
||||
case InUseStateEnum.Disposable:
|
||||
case InUseStateEnum.FeedbackPending:
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(bikeInfo.station))
|
||||
{
|
||||
// Bike available must always have a station id because bikes can only be returned at a station.
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. No station info set.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var lockType = lockModel.HasValue
|
||||
? BikeExtension.GetLockType(lockModel.Value)
|
||||
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to back end- locks.
|
||||
|
||||
try
|
||||
{
|
||||
switch (lockType)
|
||||
{
|
||||
case LockType.Backend:
|
||||
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.Sigo,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.GetAaRideType(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
dataSource,
|
||||
bikeInfo.station,
|
||||
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
|
||||
bikeInfo.GetState() == InUseStateEnum.FeedbackPending,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
miniSurvey: bikeInfo.user_miniquery != null
|
||||
? new MiniSurveyModel(new Dictionary<string, IQuestionModel> {
|
||||
{ "q1", new QuestionModel()} // Add a dummy query. Queries are not yet read from COPRI but compiled into the app.
|
||||
})
|
||||
: new MiniSurveyModel(),
|
||||
co2Saving: bikeInfo.co2saving);
|
||||
|
||||
case LockType.Bluethooth:
|
||||
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.ILockIt,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.GetAaRideType(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
dataSource,
|
||||
bikeInfo.GetBluetoothLockId(),
|
||||
bikeInfo.GetBluetoothLockGuid(),
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup());
|
||||
|
||||
default:
|
||||
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
|
||||
}
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
// Constructor reported invalid arguments (missing lock id, ....).
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Invalid response detected. Available bike with id {bikeInfo.bike} skipped. {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Creates a bike info object from copri response. </summary>
|
||||
/// <param name="bikeInfo">Copri response. </param>
|
||||
/// <param name="mailAddress">Mail address of user.</param>
|
||||
/// <param name="dateTimeProvider">Date and time provider function.</param>
|
||||
/// <param name="dataSource">Specified the source of the data.</param>
|
||||
public static BikeInfo Create(
|
||||
BikeInfoReservedOrBooked bikeInfo,
|
||||
string mailAddress,
|
||||
Func<DateTime> dateTimeProvider,
|
||||
DataSource dataSource)
|
||||
{
|
||||
if (bikeInfo == null) throw new ArgumentNullException(nameof(bikeInfo));
|
||||
|
||||
var lockModel = bikeInfo.GetLockModel();
|
||||
|
||||
if (lockModel.HasValue
|
||||
&& lockModel.Value == LockModel.BordComputer)
|
||||
{
|
||||
// Manual lock bikes are no more supported.
|
||||
Log.Error(
|
||||
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
|
||||
"Manual lock bikes are no more supported." +
|
||||
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $", station number {bikeInfo.station}" : string.Empty)}."
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
var lockType = lockModel.HasValue
|
||||
? BikeExtension.GetLockType(lockModel.Value)
|
||||
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
|
||||
|
||||
// Check if bike is a bluetooth lock bike.
|
||||
int lockSerial = bikeInfo.GetBluetoothLockId();
|
||||
Guid lockGuid = bikeInfo.GetBluetoothLockGuid();
|
||||
|
||||
switch (bikeInfo.GetState())
|
||||
{
|
||||
case InUseStateEnum.Reserved:
|
||||
try
|
||||
{
|
||||
switch (lockType)
|
||||
{
|
||||
case LockType.Bluethooth:
|
||||
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.ILockIt,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.GetAaRideType(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
dataSource,
|
||||
lockSerial,
|
||||
lockGuid,
|
||||
bikeInfo.GetUserKey(),
|
||||
bikeInfo.GetAdminKey(),
|
||||
bikeInfo.GetSeed(),
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
dateTimeProvider,
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup());
|
||||
|
||||
case LockType.Backend:
|
||||
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.Sigo,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.GetAaRideType(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
dataSource,
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
|
||||
bikeInfo.GetOperatorUri(),
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
dateTimeProvider,
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup());
|
||||
default:
|
||||
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
|
||||
}
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
// Constructor reported invalid arguments (missing lock id, ....).
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Reserved bike with id {bikeInfo.bike} skipped. {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
case InUseStateEnum.Booked:
|
||||
try
|
||||
{
|
||||
switch (lockModel)
|
||||
{
|
||||
case LockModel.ILockIt:
|
||||
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.ILockIt,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.GetAaRideType(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
dataSource,
|
||||
lockSerial,
|
||||
bikeInfo.GetBluetoothLockGuid(),
|
||||
bikeInfo.GetUserKey(),
|
||||
bikeInfo.GetAdminKey(),
|
||||
bikeInfo.GetSeed(),
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup());
|
||||
|
||||
case LockModel.BordComputer:
|
||||
throw new NotSupportedException($"Bikes with lock model of type {lockModel} are no more supported.");
|
||||
|
||||
default:
|
||||
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.Sigo,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.GetAaRideType(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
DataSource.Copri,
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
|
||||
bikeInfo.GetOperatorUri(),
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup());
|
||||
}
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
// Constructor reported invalid arguments (missing lock id, ....).
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Booked bike with id {bikeInfo.bike} skipped. {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
default:
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ShareeBike.Model.MiniSurvey;
|
||||
using ShareeBike.Repository.Response;
|
||||
|
||||
namespace ShareeBike.Model.Connector.Updater
|
||||
{
|
||||
public static class BookingFinishedModelFactory
|
||||
{
|
||||
/// <summary> Creates a booking finished object from response.</summary>
|
||||
/// <param name="response">Response to create survey object from.</param>
|
||||
public static BookingFinishedModel Create(this DoReturnResponse response)
|
||||
{
|
||||
var bookingFinished = new BookingFinishedModel
|
||||
{
|
||||
Co2Saving = response?.bike_returned.co2saving,
|
||||
RentalCosts = response?.bike_returned.total_price,
|
||||
Duration = response?.bike_returned.real_clock,
|
||||
Distance = response?.bike_returned.distance,
|
||||
};
|
||||
|
||||
if (response?.user_miniquery == null)
|
||||
|
||||
{
|
||||
return bookingFinished;
|
||||
}
|
||||
|
||||
var miniquery = response.user_miniquery;
|
||||
bookingFinished.MiniSurvey = new MiniSurveyModel
|
||||
{
|
||||
Title = miniquery.title,
|
||||
Subtitle = miniquery.subtitle,
|
||||
Footer = miniquery.footer
|
||||
};
|
||||
|
||||
foreach (var question in miniquery?.questions?.OrderBy(x => x.Key) ?? new Dictionary<string, MiniSurveyResponse.Question>().OrderBy(x => x.Key))
|
||||
{
|
||||
if (string.IsNullOrEmpty(question.Key.Trim())
|
||||
|| question.Value.query == null)
|
||||
{
|
||||
// Skip invalid entries.
|
||||
continue;
|
||||
}
|
||||
|
||||
bookingFinished.MiniSurvey.Questions.Add(
|
||||
question.Key,
|
||||
new QuestionModel());
|
||||
}
|
||||
|
||||
return bookingFinished;
|
||||
}
|
||||
}
|
||||
}
|
45
SharedBusinessLogic/Model/Connector/Updater/DriveFactory.cs
Normal file
45
SharedBusinessLogic/Model/Connector/Updater/DriveFactory.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.EngineNS;
|
||||
using ShareeBike.Repository.Response;
|
||||
|
||||
namespace ShareeBike.Model.Connector.Updater
|
||||
{
|
||||
public static class DriveFactory
|
||||
{
|
||||
public static DriveMutable Create(this BikeType bikeType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(bikeType?.engine?.manufacturer))
|
||||
{
|
||||
// Bike is has no engine
|
||||
return new DriveMutable();
|
||||
}
|
||||
|
||||
// Bike is a pedelec.
|
||||
return new DriveMutable(
|
||||
new Engine(bikeType?.engine?.manufacturer),
|
||||
new Battery.Builder
|
||||
{
|
||||
CurrentChargePercent = double.TryParse(bikeType?.battery?.charge_current_percent, out double currentChargePercent)
|
||||
? currentChargePercent
|
||||
: double.NaN,
|
||||
|
||||
CurrentChargeBars = int.TryParse(bikeType?.battery?.charge_current_bars, out int currentChargeBars)
|
||||
? (int?)currentChargeBars
|
||||
: null,
|
||||
|
||||
MaxChargeBars = int.TryParse(bikeType?.battery?.charge_max_bars, out int maxChargeBars)
|
||||
? (int?)maxChargeBars
|
||||
: null,
|
||||
|
||||
IsBackendAccessible = bikeType?.battery?.backend_accessible != null && int.TryParse(bikeType.battery.backend_accessible, out int accessible)
|
||||
? (bool?)(accessible > 0)
|
||||
: null,
|
||||
|
||||
IsHidden = bikeType?.battery?.hidden != null && int.TryParse(bikeType.battery.hidden, out int hidden)
|
||||
? (bool?)(hidden > 0)
|
||||
: null
|
||||
}.Build());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS;
|
||||
|
||||
namespace ShareeBike.Model.Connector.Updater
|
||||
{
|
||||
public static class RentalDescriptionFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates rental description object from JSON- tariff description object.
|
||||
/// </summary>
|
||||
/// <param name="rentalDesciption">Source JSON object.</param>
|
||||
/// <returns>Tariff description object.</returns>
|
||||
|
||||
public static RentalDescription Create(this Repository.Response.RentalDescription rentalDesciption)
|
||||
{
|
||||
RentalDescription.TariffElement CreateTarifEntry(string[] elementValue) =>
|
||||
new RentalDescription.TariffElement
|
||||
{
|
||||
Description = elementValue != null && elementValue.Length > 0 ? elementValue[0] : string.Empty,
|
||||
Value = elementValue != null && elementValue.Length > 1 ? elementValue[1] : string.Empty,
|
||||
};
|
||||
|
||||
RentalDescription.InfoElement CreateInfoElement(string[] elementValue) =>
|
||||
new RentalDescription.InfoElement
|
||||
{
|
||||
Key = elementValue != null && elementValue.Length > 0 ? elementValue[0] : string.Empty,
|
||||
Value = elementValue != null && elementValue.Length > 1 ? elementValue[1] : string.Empty,
|
||||
};
|
||||
|
||||
// Read tariff elements.
|
||||
var tarifEntries = rentalDesciption?.tarif_elements != null
|
||||
? rentalDesciption.tarif_elements.Select(x => new
|
||||
{
|
||||
x.Key,
|
||||
Value = CreateTarifEntry(x.Value)
|
||||
}).ToLookup(x => x.Key, x => x.Value).ToDictionary(x => x.Key, x => x.First())
|
||||
: new Dictionary<string, RentalDescription.TariffElement>();
|
||||
|
||||
// Read info elements.
|
||||
var InfoEntries = rentalDesciption?.rental_info != null
|
||||
? rentalDesciption.rental_info.Select(x => new
|
||||
{
|
||||
x.Key,
|
||||
Value = CreateInfoElement(x.Value)
|
||||
}).ToLookup(x => x.Key, x => x.Value).ToDictionary(x => x.Key, x => x.First())
|
||||
: new Dictionary<string, RentalDescription.InfoElement>();
|
||||
|
||||
var bike = new RentalDescription
|
||||
{
|
||||
Name = rentalDesciption?.name ?? string.Empty,
|
||||
Id = int.TryParse(rentalDesciption?.id ?? string.Empty, out int number) ? number : (int?)null,
|
||||
MaxReservationTimeSpan = rentalDesciption.GetMaxReservationTimeSpan(),
|
||||
TariffEntries = tarifEntries,
|
||||
InfoEntries = InfoEntries
|
||||
};
|
||||
|
||||
return bike;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
using System.Globalization;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Repository.Response;
|
||||
|
||||
namespace ShareeBike.Model.Connector.Updater
|
||||
{
|
||||
public static class TariffDescriptionFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates rental description object from JSON- tarif description object.
|
||||
/// </summary>
|
||||
/// <param name="tariffDesciption">Source JSON object.</param>
|
||||
/// <returns>Tariff description object.</returns>
|
||||
public static Bikes.BikeInfoNS.RentalDescription Create(this TariffDescription tariffDesciption)
|
||||
{
|
||||
var bike = new Bikes.BikeInfoNS.RentalDescription
|
||||
{
|
||||
Name = tariffDesciption?.name,
|
||||
#if USCSHARP9
|
||||
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : null,
|
||||
#else
|
||||
Id = int.TryParse(tariffDesciption?.number, out int number) ? number : (int?)null,
|
||||
#endif
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.free_hours)
|
||||
&& double.TryParse(tariffDesciption?.free_hours, NumberStyles.Any, CultureInfo.InvariantCulture, out double freeHours))
|
||||
{
|
||||
// Free time. Unit hours,format floating point number.
|
||||
bike.TariffEntries.Add("1", new Bikes.BikeInfoNS.RentalDescription.TariffElement
|
||||
{
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionFreeTimePerSession,
|
||||
Value = string.Format("{0} {1}", freeHours.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionHour)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.eur_per_hour)
|
||||
&& double.TryParse(tariffDesciption?.eur_per_hour, NumberStyles.Any, CultureInfo.InvariantCulture, out double euroPerHour))
|
||||
{
|
||||
// Euro per hour. Format floating point.
|
||||
bike.TariffEntries.Add("2", new Bikes.BikeInfoNS.RentalDescription.TariffElement
|
||||
{
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionFeeEuroPerHour,
|
||||
Value = string.Format("{0} {1}", euroPerHour.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionEuroPerHour)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.max_eur_per_day)
|
||||
&& double.TryParse(tariffDesciption.max_eur_per_day, NumberStyles.Any, CultureInfo.InvariantCulture, out double maxEuroPerDay))
|
||||
{
|
||||
// Max euro per day. Format floating point.
|
||||
bike.TariffEntries.Add("3", new Bikes.BikeInfoNS.RentalDescription.TariffElement
|
||||
{
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionMaxFeeEuroPerDay,
|
||||
Value = string.Format("{0} {1}", maxEuroPerDay.ToString("0.00"), AppResources.MessageBikesManagementMaxFeeEuroPerDay)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.abo_eur_per_month)
|
||||
&& double.TryParse(tariffDesciption.abo_eur_per_month, NumberStyles.Any, CultureInfo.InvariantCulture, out double aboEuroPerMonth))
|
||||
{
|
||||
// Abo per month
|
||||
bike.TariffEntries.Add("4", new Bikes.BikeInfoNS.RentalDescription.TariffElement
|
||||
{
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionAboEuroPerMonth,
|
||||
Value = string.Format("{0} {1}", aboEuroPerMonth.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionEuroPerMonth)
|
||||
});
|
||||
}
|
||||
|
||||
return bike;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
149
SharedBusinessLogic/Model/Connector/Updater/UpdaterJSON.cs
Normal file
149
SharedBusinessLogic/Model/Connector/Updater/UpdaterJSON.cs
Normal file
|
@ -0,0 +1,149 @@
|
|||
using System;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BC;
|
||||
using ShareeBike.Model.State;
|
||||
using ShareeBike.Model.Stations;
|
||||
using ShareeBike.Model.User.Account;
|
||||
using ShareeBike.Repository.Exception;
|
||||
using ShareeBike.Repository.Response;
|
||||
using ShareeBike.Repository.Response.Stations;
|
||||
using ShareeBike.Services.CopriApi;
|
||||
using IBikeInfoMutable = ShareeBike.Model.Bikes.BikeInfoNS.BC.IBikeInfoMutable;
|
||||
|
||||
namespace ShareeBike.Model.Connector.Updater
|
||||
{
|
||||
/// <summary>
|
||||
/// Connects ShareeBike app to copri using JSON as input data format.
|
||||
/// </summary>
|
||||
/// <todo>Rename to UpdateFromCopri.</todo>
|
||||
public static class UpdaterJSON
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all station for station provider and add them into station list.
|
||||
/// </summary>
|
||||
/// <param name="stationsAllResponse">List of stations to update.</param>
|
||||
public static StationDictionary GetStationsAllMutable(this StationsAvailableResponse stationsAllResponse)
|
||||
{
|
||||
// Get stations from Copri/ file/ memory, ....
|
||||
if (stationsAllResponse == null
|
||||
|| stationsAllResponse.stations == null)
|
||||
{
|
||||
// Latest list of stations could not be retrieved from provider.
|
||||
return new StationDictionary();
|
||||
}
|
||||
|
||||
Version.TryParse(stationsAllResponse.copri_version, out Version copriVersion);
|
||||
|
||||
var stations = new StationDictionary(version: copriVersion);
|
||||
|
||||
foreach (var station in stationsAllResponse.stations)
|
||||
{
|
||||
if (stations.GetById(station.Value.station) != null)
|
||||
{
|
||||
// Can not add station to list of station. Id is not unique.
|
||||
throw new InvalidResponseException<StationsAvailableResponse>(
|
||||
string.Format("Station id {0} is not unique.", station.Value.station), stationsAllResponse);
|
||||
}
|
||||
|
||||
stations.Add(station.Value.GetStation());
|
||||
}
|
||||
|
||||
return stations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets general data from COPRI response.
|
||||
/// </summary>
|
||||
/// <param name="response">Response to get data from.</param>
|
||||
/// <returns>General data object initialized form COPRI response.</returns>
|
||||
public static GeneralData GetGeneralData(this ResponseBase response)
|
||||
=> new GeneralData(
|
||||
response.init_map.GetMapSpan(),
|
||||
response.merchant_message,
|
||||
response.TryGetCopriVersion(out Version copriVersion)
|
||||
? new Version(0, 0)
|
||||
: copriVersion,
|
||||
new ResourceUrls(response.tariff_info_html, response.bike_info_html, response.agb_html, response.privacy_html, response.impress_html));
|
||||
|
||||
/// <summary> Gets account object from login response.</summary>
|
||||
/// <param name="merchantId">Needed to extract cookie from authorization response.</param>
|
||||
/// <param name="loginResponse">Response to get session cookie and debug level from.</param>
|
||||
/// <param name="mail">Mail address needed to construct a complete account object (is not part of response).</param>
|
||||
/// <param name="password">Password needed to construct a complete account object (is not part of response).</param>
|
||||
public static IAccount GetAccount(
|
||||
this AuthorizationResponse loginResponse,
|
||||
string merchantId,
|
||||
string mail,
|
||||
string password)
|
||||
{
|
||||
if (loginResponse == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(loginResponse));
|
||||
}
|
||||
|
||||
return new Account(
|
||||
mail,
|
||||
password,
|
||||
loginResponse.GetIsAgbAcknowledged(),
|
||||
loginResponse.authcookie?.Replace(merchantId, ""),
|
||||
loginResponse.GetGroup(),
|
||||
loginResponse.debuglevel == 1
|
||||
? Permissions.All :
|
||||
(Permissions)loginResponse.debuglevel);
|
||||
}
|
||||
|
||||
/// <summary> Load bike object from booking response. </summary>
|
||||
/// <param name="bike">Bike object to load from response.</param>
|
||||
/// <param name="bikeInfo">Booking response.</param>
|
||||
/// <param name="mailAddress">Mail address of user which books bike.</param>
|
||||
/// <param name="notifyLevel">Controls whether notify property changed events are fired or not.</param>
|
||||
public static void Load(
|
||||
this IBikeInfoMutable bike,
|
||||
BikeInfoReservedOrBooked bikeInfo,
|
||||
string mailAddress,
|
||||
NotifyPropertyChangedLevel notifyLevel = NotifyPropertyChangedLevel.All)
|
||||
{
|
||||
if (bike is Bikes.BikeInfoNS.BluetoothLock.BikeInfoMutable btBikeInfo)
|
||||
{
|
||||
btBikeInfo.LockInfo.Load(
|
||||
bikeInfo.GetBluetoothLockId(),
|
||||
bikeInfo.GetBluetoothLockGuid(),
|
||||
bikeInfo.GetSeed(),
|
||||
bikeInfo.GetUserKey(),
|
||||
bikeInfo.GetAdminKey());
|
||||
}
|
||||
|
||||
var l_oState = bikeInfo.GetState();
|
||||
switch (l_oState)
|
||||
{
|
||||
case InUseStateEnum.Disposable:
|
||||
bike.State.Load(
|
||||
InUseStateEnum.Disposable,
|
||||
notifyLevel: notifyLevel);
|
||||
break;
|
||||
|
||||
case InUseStateEnum.Reserved:
|
||||
bike.State.Load(
|
||||
InUseStateEnum.Reserved,
|
||||
bikeInfo.GetFrom(),
|
||||
bikeInfo.rental_description.GetMaxReservationTimeSpan(),
|
||||
mailAddress,
|
||||
bikeInfo.timeCode,
|
||||
notifyLevel);
|
||||
break;
|
||||
|
||||
case InUseStateEnum.Booked:
|
||||
bike.State.Load(
|
||||
InUseStateEnum.Booked,
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress: mailAddress,
|
||||
code: bikeInfo.timeCode,
|
||||
notifyLevel: notifyLevel);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception(string.Format("Unexpected bike state detected. state is {0}.", l_oState));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue