From 31717c6c5efe72106ee7ff2b4a39901bece07041 Mon Sep 17 00:00:00 2001
From: Tibor Bossanyi <tibor.bossanyi@aitrainer.app>
Date: Wed, 1 Mar 2023 17:44:41 +0100
Subject: [PATCH] v1.0.12 customer properties and membership

---
 .gitignore                              |   6 +-
 .vscode/settings.json                   |   9 ++
 README.md                               |   3 +
 lib/model/customer.dart                 |  11 +++
 lib/model/customer_membership.dart      |  25 ++---
 lib/model/customer_property.dart        |  14 +--
 lib/repository/customer_repository.dart |  30 ++++++
 pubspec.yaml                            |   2 +-
 test/customer_test.dart                 | 118 ++++++++++++++++++++++++
 9 files changed, 193 insertions(+), 25 deletions(-)
 create mode 100644 .vscode/settings.json
 create mode 100644 test/customer_test.dart

diff --git a/.gitignore b/.gitignore
index b912244..5b6cfad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,8 +25,8 @@ migrate_working_dir/
 # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
 /pubspec.lock
 **/doc/api/
-.dart_tool/
 .packages
 build/
-.flutter-plugins-dependencies
-.flutter-plugins
\ No newline at end of file
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..b211e21
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,9 @@
+{
+    "dart.lineLength": 150,
+    "[dart]": {
+        "editor.rulers": [
+            150
+        ],
+    },
+    "editor.formatOnSave": true
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index b5f3890..54c9c5b 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,8 @@
 Workout Test and Diet 4 You Common Util Functions
 
+Version 1.0.12
+    CustomerProperty and CustomerMembership fromJson
+
 Version 1.0.11
     Sentry and logging only in debugMode
     
diff --git a/lib/model/customer.dart b/lib/model/customer.dart
index 7c27104..80dca25 100644
--- a/lib/model/customer.dart
+++ b/lib/model/customer.dart
@@ -1,5 +1,6 @@
 import 'dart:collection';
 import 'package:intl/intl.dart';
+import 'package:workouttest_util/model/customer_membership.dart';
 
 import 'customer_property.dart';
 
@@ -31,6 +32,8 @@ class Customer {
   int? lifeLong;
 
   LinkedHashMap<String, CustomerProperty> properties = LinkedHashMap();
+  List<CustomerProperty> customerProperties = [];
+  List<CustomerMembership> memberships = [];
 
   Customer(
       {customerId,
@@ -83,6 +86,14 @@ class Customer {
 
     dateAdd = json['dateAdd'] == null ? DateTime.parse("0000-00-00") : DateTime.parse(json['dateAdd']);
     dateChange = json['dateChange'] == null ? DateTime.parse("0000-00-00") : DateTime.parse(json['dateChange']);
+
+    if (json['properties'] != null && json['properties'].length > 0) {
+      customerProperties = json['properties'].map<CustomerProperty>((detail) => CustomerProperty.fromJson(detail)).toList();
+    }
+
+    if (json['memberships'] != null && json['memberships'].length > 0) {
+      memberships = json['memberships'].map<CustomerMembership>((detail) => CustomerMembership.fromJson(detail)).toList();
+    }
   }
 
   Map<String, dynamic> toJson() => {
diff --git a/lib/model/customer_membership.dart b/lib/model/customer_membership.dart
index f4f3b63..408557b 100644
--- a/lib/model/customer_membership.dart
+++ b/lib/model/customer_membership.dart
@@ -1,21 +1,22 @@
+import 'package:intl/intl.dart';
+
 class CustomerMembership {
   late int membershipId;
-  late int customerId;
-  late DateTime startDate;
-
+  int? customerId;
+  DateTime? startDate;
 
   CustomerMembership.fromJson(Map json) {
     membershipId = json['membershipId'];
-    customerId = json['customerId'];
-    startDate = json['startDate'];
+    customerId = json['customerId'] ?? 0;
+    startDate = json['startDate'] == null ? null : DateTime.parse(json['startDate']);
   }
 
-Map<String, dynamic> toJson() =>  {
-      "membershipId": membershipId,
-      "customerId": customerId,
-      "startDate": startDate,
-    };
+  Map<String, dynamic> toJson() => {
+        "membershipId": membershipId,
+        "customerId": customerId ?? 0,
+        "startDate": startDate == null ? "" : DateFormat('yyyy-MM-dd HH:mm:ss').format(startDate!),
+      };
 
   @override
-  String toString() => toJson().toString();  
-}
\ No newline at end of file
+  String toString() => toJson().toString();
+}
diff --git a/lib/model/customer_property.dart b/lib/model/customer_property.dart
index bebf0ea..20e7e19 100644
--- a/lib/model/customer_property.dart
+++ b/lib/model/customer_property.dart
@@ -4,7 +4,7 @@ import '../util/logging.dart';
 class CustomerProperty with Logging {
   int? customerPropertyId;
   late int propertyId;
-  late int customerId;
+  int? customerId;
   DateTime? dateAdd;
   String? dateYmd;
   String? dateYm;
@@ -12,16 +12,12 @@ class CustomerProperty with Logging {
   late double propertyValue;
   bool newData = false;
 
-  CustomerProperty(
-      {required propertyId,
-      required customerId,
-      required dateAdd,
-      required propertyValue});
+  CustomerProperty({required propertyId, required customerId, required dateAdd, required propertyValue});
 
   CustomerProperty.fromJson(Map json) {
     customerPropertyId = json['customerPropertyId'];
     propertyId = json['propertyId'];
-    customerId = json['customerId'];
+    customerId = json['customerId'] ?? 0;
     dateAdd = DateTime.parse(json['dateAdd']);
 
     if (dateAdd != null) {
@@ -40,14 +36,14 @@ class CustomerProperty with Logging {
       return {
         "customerPropertyId": customerPropertyId,
         "propertyId": propertyId,
-        "customerId": customerId,
+        "customerId": customerId ?? 0,
         "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(dateAdd!),
         "propertyValue": propertyValue
       };
     } else {
       return {
         "propertyId": propertyId,
-        "customerId": customerId,
+        "customerId": customerId ?? 0,
         "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(dateAdd!),
         "propertyValue": propertyValue
       };
diff --git a/lib/repository/customer_repository.dart b/lib/repository/customer_repository.dart
index e419093..e5ba01d 100644
--- a/lib/repository/customer_repository.dart
+++ b/lib/repository/customer_repository.dart
@@ -566,4 +566,34 @@ class CustomerRepository with Logging {
     }
     return allProperties;
   }
+
+  void initCustomerProperties() {
+    List<Property>? properties = Cache().getProperties();
+    Customer? customer = Cache().userLoggedIn;
+    if (customer == null || customer.customerProperties.isEmpty || properties == null) {
+      return;
+    }
+
+    for (var property in properties) {
+      CustomerProperty? customerProperty = getCustomerPropertyById(property.propertyId);
+      if (customerProperty != null) {
+        customer.properties[property.propertyName] = customerProperty;
+      }
+    }
+  }
+
+  CustomerProperty? getCustomerPropertyById(int id) {
+    CustomerProperty? property;
+    Customer? customer = Cache().userLoggedIn;
+    if (customer == null) {
+      return property;
+    }
+    for (var customerProperty in customer.customerProperties) {
+      if (customerProperty.propertyId == id) {
+        property = customerProperty;
+        break;
+      }
+    }
+    return property;
+  }
 }
diff --git a/pubspec.yaml b/pubspec.yaml
index 139b67d..d4fdfa5 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
 name: workouttest_util
 description: Workout Test app and web functions.
-version: 1.0.10
+version: 1.0.12
 homepage:
 
 environment:
diff --git a/test/customer_test.dart b/test/customer_test.dart
new file mode 100644
index 0000000..50932be
--- /dev/null
+++ b/test/customer_test.dart
@@ -0,0 +1,118 @@
+import 'dart:convert';
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:workouttest_util/model/cache.dart';
+import 'package:workouttest_util/model/customer.dart';
+import 'package:workouttest_util/model/property.dart';
+import 'package:workouttest_util/repository/customer_repository.dart';
+import 'dart:collection';
+import 'package:intl/intl.dart';
+
+main() {
+  setUp(() {
+    String propertyJson = '''
+[
+	{
+		"propertyId": 1,
+		"propertyName": "Weight",
+		"propertyUnit": "kg",
+		"translations": [
+			{
+				"translationId": 11,
+				"languageCode": "hu",
+				"propertyName": "Tömeg"
+			}
+		]
+	},
+	{
+		"propertyId": 2,
+		"propertyName": "Height",
+		"propertyUnit": "cm",
+		"translations": [
+			{
+				"translationId": 12,
+				"languageCode": "hu",
+				"propertyName": "Magasság"
+			}
+		]
+	},
+	{
+		"propertyId": 3,
+		"propertyName": "Chest",
+		"propertyUnit": "cm",
+		"translations": [
+			{
+				"translationId": 13,
+				"languageCode": "hu",
+				"propertyName": "Mell"
+			}
+		]
+	}
+  ]
+''';
+    Iterable json = jsonDecode(propertyJson);
+    final List<Property> properties = json.map((property) => Property.fromJson(property)).toList();
+    Cache().setProperties(properties);
+  });
+
+  group('customer', () {
+    test('decode from json successful', () async {
+      String json = '''{
+  "name": "",
+  "firstname": "Andi",
+  "email": "mr@aitrainer.app",
+  "age": 0,
+  "sex": "m",
+  "active": "Y",
+  "dateAdd": "2023-02-25 11:19:30",
+  "dataPolicyAllowed": 1,
+  "password": "2a10O5HXhhb29LC8pNiv1uBIoOFRGOmDMtdeMJtVkfhzAjB/ejrO9D486",
+  "birthYear": 1974,
+  "goal": "health_keep",
+  "fitnessLevel": "intermediate",
+  "firebaseUid": "ih74dupj2ncyROAaeyK8oAXYOWk2",
+  "emailSubscription": 0,
+  "firebaseRegToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjE1YzJiNDBhYTJmMzIyNzk4NjY2YTZiMzMyYWFhMDNhNjc3MzAxOWIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vZGlldDR5b3UtY2I1NDAiLCJhdWQiOiJkaWV0NHlvdS1jYjU0MCIsImF1dGhfdGltZSI6MTY3NzMyMDM3MSwidXNlcl9pZCI6ImloNzRkdXBqMm5jeVJPQWFleUs4b0FYWU9XazIiLCJzdWIiOiJpaDc0ZHVwajJuY3lST0FhZXlLOG9BWFlPV2syIiwiaWF0IjoxNjc3MzIwMzcxLCJleHAiOjE2NzczMjM5NzEsImVtYWlsIjoibXJAYWl0cmFpbmVyLmFwcCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJtckBhaXRyYWluZXIuYXBwIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.yds_4NSc1m7U7q6y1jdHy61Z1Y_4weOWfC_mbvzQsGLqsuOuP_SM6OvhqQOjywAWGhvm709mydm9nWdhhPNDNTcC5pn8Xl770GYoMF_8tLPae8Mrw-9ppFvXNHXg0kKpl2uIirjMhZM19fq4HBLJPAReQ8-8FCHfodXRd5TH5EWSZnZ-TzdwvKaitfjn_-2w4tA1WepH4XhCwP908NG-U6IUwBOsi_aoQpQwSJWL9HwW1pTsYSE0DubfKOmsMBH3WaVkkJfcL1IOGBR4TK-vimkfmP2VnU3F88GF583b1FKw-JZ6ovOBy4jHnL02k_yAQksMwHXeaSGMwulWdjxqHQ",
+  "customerId": 56,
+  "properties": [
+    {
+      "customerPropertyId": 3,
+      "propertyId": 1,
+      "propertyValue": 66.0,
+      "dateAdd": "2023-02-25 11:19:30",
+      "goal": false
+    },
+    {
+      "customerPropertyId": 4,
+      "propertyId": 2,
+      "propertyValue": 178.0,
+      "dateAdd": "2023-02-25 11:19:30",
+      "goal": false
+    }
+  ],
+  "memberships": [
+    {
+      "id": 2,
+      "membershipId": 2,
+      "startDate": "2023-02-25 11:19:30"
+    }
+  ]
+}''';
+
+      Customer customer = Customer.fromJson(jsonDecode(json));
+      expect(customer.customerId, 56);
+      expect(customer.customerProperties.length, 2);
+      expect(customer.customerProperties[0].propertyValue, 66);
+      expect(customer.customerProperties[1].propertyId, 2);
+      expect(customer.memberships.length, 1);
+      expect(customer.memberships[0].membershipId, 2);
+      Cache().userLoggedIn = customer;
+      CustomerRepository repository = CustomerRepository();
+      repository.initCustomerProperties();
+
+      customer = Cache().userLoggedIn!;
+      expect(customer.properties.length, 2);
+      expect(customer.getProperty("Weight"), 66);
+    });
+  });
+}