From ad20f104162e70073bac6cd6ed2ac15809e44d17 Mon Sep 17 00:00:00 2001 From: magsyg Date: Wed, 4 May 2022 16:59:01 +0200 Subject: [PATCH 1/2] add showroom display to showroom and company --- backend/companies/admin.py | 11 ++- backend/companies/views.py | 2 +- backend/main/management/commands/myseed.py | 3 +- .../main/management/commands/showroom_seed.py | 77 +++++++++++++++++++ frontend/src/components/AppointmentInfo.js | 11 +-- frontend/src/components/LocationInfo.js | 9 ++- .../appointments/showroom/ShowroomScreen.js | 1 + .../company/contact/ContactBrandScreen.js | 5 +- .../company/contact/NewContactBrand.js | 1 + .../company/contact/ScheduleContactBrand.js | 2 +- 10 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 backend/main/management/commands/showroom_seed.py diff --git a/backend/companies/admin.py b/backend/companies/admin.py index 9256072..9f0ced8 100644 --- a/backend/companies/admin.py +++ b/backend/companies/admin.py @@ -2,7 +2,7 @@ from django.contrib.auth import get_user_model -from .models import Brand, BrandRetailerRelation, Retailer, CompanyCode, Note +from .models import Brand, BrandRetailerRelation, Retailer, CompanyCode, Note, ShowRoom User = get_user_model() # Register your models here. @@ -45,4 +45,11 @@ class BrandRetailerRelationAdmin(admin.ModelAdmin): class NoteAdmin(admin.ModelAdmin): list_display = ['company', 'creator','timestamp'] search_fields = ['company', 'creator'] - ordering = ['id','timestamp'] \ No newline at end of file + ordering = ['id','timestamp'] + + +@admin.register(ShowRoom) +class ShowRoomAdmin(admin.ModelAdmin): + list_display = ['brand', 'address','city','country'] + search_fields = ['brand', 'address','city','country'] + ordering = ['id'] \ No newline at end of file diff --git a/backend/companies/views.py b/backend/companies/views.py index 5d0e677..4f2fdae 100644 --- a/backend/companies/views.py +++ b/backend/companies/views.py @@ -211,7 +211,7 @@ def get_object(self, pk): def get(self, request, pk, format=None): brand = self.get_object(pk) - serializer = SimpleBrandSerializer(brand) # Does not return the contacts of that company + serializer = BrandSerializer(brand) # Does not return the contacts of that company appointments = Appointment.objects.filter(retailer__retailer=request.user.company, brands=brand) appointments = SimpleAppointmentSerializer(appointments, many=True) diff --git a/backend/main/management/commands/myseed.py b/backend/main/management/commands/myseed.py index 3dbd5ce..f7cf23f 100644 --- a/backend/main/management/commands/myseed.py +++ b/backend/main/management/commands/myseed.py @@ -70,7 +70,7 @@ def populate(self): seeder.add_entity(companies_models.Brand, 5, { 'name': lambda x: seeder.faker.word(), }) - + companies = companies_models.Company.objects.all() seeder.execute() @@ -83,6 +83,7 @@ def populate(self): random_logo = random.choice(logos) image_path = (placeholder_logo_path / random_logo).resolve() company.logo = ImageFile(open(image_path, mode='rb'), name=random_logo) + company.save() for user in User.objects.all(): # Set random profile picture and company diff --git a/backend/main/management/commands/showroom_seed.py b/backend/main/management/commands/showroom_seed.py new file mode 100644 index 0000000..d35cc59 --- /dev/null +++ b/backend/main/management/commands/showroom_seed.py @@ -0,0 +1,77 @@ +# imports +import os +from pathlib import Path +import random +from time import timezone +from django_seed import Seed +from faker import Faker +from PIL import Image + +from django.core.files.images import ImageFile +from django.core.management.base import BaseCommand +from django.contrib.auth import get_user_model +from django.contrib.auth import models as auth_models + +from companies import models as companies_models +from appointments import models as appointments_models +# End: imports ----------------------------------------------------------------- + +# Settings: + +User = get_user_model() + + +class Command(BaseCommand): + + def add_arguments(self, parser): + parser.add_argument( + '--noinput', + '--no-input', + action='store_false', + dest='interactive', + help='Tells Django to NOT prompt the user for input of any kind.', + ) + + def confirmation(self): + answer = None + yes = ['yes', 'y'] + no = ['no', 'n'] + print('== This command will:') + print('\t 1. Attempt to seed all models') + + print('\n== Are you sure? DOUBLE-CHECK that this is not production server ==') + + while answer not in yes + no: + answer = input("Type 'y' or 'n': ").lower() + + return answer in yes + + def populate(self): + # Use after myseed + fake = Faker() + seeder = Seed.seeder() + seeder.faker.seed_instance() + + total_showrooms=len(companies_models.Brand.objects.filter(showrooms=None)) + if total_showrooms > 0: + seeder.add_entity(companies_models.ShowRoom, total_showrooms, { + 'brand': lambda x: companies_models.Brand.objects.filter(showrooms=None).first() + }) + + seeder.execute() + + for brand in companies_models.Brand.objects.filter(current_showroom=None): + brand.current_showroom = brand.showrooms.first() + brand.save() + + + def handle(self, *args, **options): + + interactive = options['interactive'] + if interactive: + if not self.confirmation(): + print('== ABORT ==') + return + self.populate() + + # End of handle diff --git a/frontend/src/components/AppointmentInfo.js b/frontend/src/components/AppointmentInfo.js index 5f8a437..6b767b4 100644 --- a/frontend/src/components/AppointmentInfo.js +++ b/frontend/src/components/AppointmentInfo.js @@ -2,6 +2,7 @@ import React from 'react' import { StyleSheet, View, TouchableOpacity, Text } from 'react-native' import { theme } from '../core/theme' import { transformNiceDate } from '../utils/date_management' +import LocationInfo from './LocationInfo' import OutlinedButton from './OutlinedButton' export default function AppointmentInfo({containerStyle, appointment}) { @@ -11,16 +12,12 @@ export default function AppointmentInfo({containerStyle, appointment}) { {appointment.start_time.slice(0,5)} - {appointment.end_time.slice(0,5)} {transformNiceDate(appointment.date)} + {appointment.appointment_type === 'SR' && + + } - {appointment.address} {appointment.appointment_type === 'TR' && Pass } - {appointment.appointment_type === 'SR' && - - Door Code: 952 - Floor: Ground - - } ) } diff --git a/frontend/src/components/LocationInfo.js b/frontend/src/components/LocationInfo.js index 5cc7e2d..111916c 100644 --- a/frontend/src/components/LocationInfo.js +++ b/frontend/src/components/LocationInfo.js @@ -5,17 +5,24 @@ import { transformNiceDate } from '../utils/date_management' import OutlinedButton from './OutlinedButton' export default function LocationInfo({containerStyle, item}) { + if (typeof item !== "undefined") { return ( + {(item.address != null && item.city != null) && {item.address} {item.city} + } {(item.doorcode != null && item.doorcode.length > 0) && Door Code: {item.doorcode} } {(item.floor != null && item.floor.length > 0) && Floor: {item.floor} } - ) + ) + } + else { + return() + } } //TODO add check for door, address and floor const styles = StyleSheet.create({ diff --git a/frontend/src/screens/appointments/showroom/ShowroomScreen.js b/frontend/src/screens/appointments/showroom/ShowroomScreen.js index 6a14150..f98f5cf 100644 --- a/frontend/src/screens/appointments/showroom/ShowroomScreen.js +++ b/frontend/src/screens/appointments/showroom/ShowroomScreen.js @@ -23,6 +23,7 @@ import CompanyLogo from '../../../components/CompanyLogo'; import CurrentUserContext from '../../../../Context'; import BackgroundAuth from '../../../components/BackgroundAuth'; import api from '../../../../api'; +import LocationInfo from '../../../components/LocationInfo'; export default function ShowroomScreen({ route, navigation }) { diff --git a/frontend/src/screens/company/contact/ContactBrandScreen.js b/frontend/src/screens/company/contact/ContactBrandScreen.js index 09f9303..d101bd1 100644 --- a/frontend/src/screens/company/contact/ContactBrandScreen.js +++ b/frontend/src/screens/company/contact/ContactBrandScreen.js @@ -50,6 +50,9 @@ export default function ContactBrandScreen({ route, navigation }) { useEffect(() => { api.get(`/companies/brand/${brand_id}/profile/`).then((response) => { setBrand(response.data.brand) + console.log("-------------------------") + console.log(response.data.brand.current_showroom) + console.log("-------------------------") setAppointments(response.data.appointments) }).catch(function (error) { @@ -84,7 +87,7 @@ export default function ContactBrandScreen({ route, navigation }) {
{brand.name}
- + Lookbook Line Sheet diff --git a/frontend/src/screens/company/contact/NewContactBrand.js b/frontend/src/screens/company/contact/NewContactBrand.js index 861e794..bab2bbb 100644 --- a/frontend/src/screens/company/contact/NewContactBrand.js +++ b/frontend/src/screens/company/contact/NewContactBrand.js @@ -60,6 +60,7 @@ export default function NewContactBrandScreen({ route, navigation }) { setSuccessmodal(false); api.get(`/companies/brand/${brand_id}/profile/`).then((response) => { setBrand(response.data.brand) + console.log(response.data.brand.current_showroom) setAppointments(response.data.appointments) }).catch(function (error) { diff --git a/frontend/src/screens/company/contact/ScheduleContactBrand.js b/frontend/src/screens/company/contact/ScheduleContactBrand.js index 27d89b6..dae7fad 100644 --- a/frontend/src/screens/company/contact/ScheduleContactBrand.js +++ b/frontend/src/screens/company/contact/ScheduleContactBrand.js @@ -143,7 +143,7 @@ export default function ScheduleContactBrandScreen({ route, navigation }) { - + Date: Wed, 4 May 2022 17:18:13 +0200 Subject: [PATCH 2/2] add form errors to showroom --- backend/companies/models.py | 16 +++++++++++---- .../SettingsShowroomCreate.js | 20 +++++++++++++++++-- .../showroomsettings/SettingsShowroomEdit.js | 20 +++++++++++++++++-- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/backend/companies/models.py b/backend/companies/models.py index 07c218d..92ce05a 100644 --- a/backend/companies/models.py +++ b/backend/companies/models.py @@ -83,8 +83,8 @@ class BrandRetailerRelation(models.Model): class ShowRoom(models.Model): brand = models.ForeignKey(Company, null=False, blank=False, on_delete=models.CASCADE, related_name="showrooms", verbose_name="Brand") - doorcode = models.CharField(max_length=32, null=True, blank=False, verbose_name="Door code") - floor = models.CharField(max_length=10, null=True, blank=False, verbose_name="Floor") + doorcode = models.CharField(max_length=10, null=True, blank=True, verbose_name="Door code") + floor = models.CharField(max_length=10, null=True, blank=True, verbose_name="Floor") # Location info address = models.CharField(max_length=100, null=False, blank=False, verbose_name="Address") @@ -103,9 +103,17 @@ def __str__(self): def clean(self): cleaned_data = super().clean() + errors = {} if self.brand.get_correct_model().company_type != Brand.company_type: - raise ValidationError("Company is not of type brand") - + errors['brand'] = 'Company is not of type brand' + if self.doorcode and not self.doorcode.isnumeric(): + errors['doorcode'] = "Door code is not numeric" + if self.date_range_start > self.date_range_end: + errors['date_range_start'] = 'Start date can not be after end date' + if self.hours_start > self.hours_end: + errors['hours_start'] = 'Start time can not be after end time' + if errors: + raise ValidationError(errors) def is_current(self): return self.brand.get_correct_model().current_showroom == self \ No newline at end of file diff --git a/frontend/src/screens/company/settings/showroomsettings/SettingsShowroomCreate.js b/frontend/src/screens/company/settings/showroomsettings/SettingsShowroomCreate.js index 9925ccb..c2c2aad 100644 --- a/frontend/src/screens/company/settings/showroomsettings/SettingsShowroomCreate.js +++ b/frontend/src/screens/company/settings/showroomsettings/SettingsShowroomCreate.js @@ -100,8 +100,24 @@ export default function SettingsShowroomCreate({ route, navigation }) { if (error.response) { // Request made and server responded console.log(error.response.data); - console.log(error.response.status); - console.log(error.response.headers); + if (error.response.data.hasOwnProperty("address")) { + setAddress({value:address.value, error:error.response.data.address[0]}) + } + if (error.response.data.hasOwnProperty("city")) { + setCity({value:city.value, error:error.response.data.city[0]}) + } + if (error.response.data.hasOwnProperty("country")) { + setCountry({value:country.value, error:error.response.data.country[0]}) + } + if (error.response.data.hasOwnProperty("doorcode")) { + setDoorCode({value:doorCode.value, error:error.response.data.doorcode[0]}) + } + if (error.response.data.hasOwnProperty("start_hours")) { + setStartTime({value:startTime.value, error:error.response.data.start_hours[0]}) + } + if (error.response.data.hasOwnProperty("date_range_start")) { + setStartDate({value:startDate.value, error:error.response.data.date_range_start[0]}) + } } else if (error.request) { // The request was made but no response was received console.log(error.request); diff --git a/frontend/src/screens/company/settings/showroomsettings/SettingsShowroomEdit.js b/frontend/src/screens/company/settings/showroomsettings/SettingsShowroomEdit.js index 0261d1a..97ba7fd 100644 --- a/frontend/src/screens/company/settings/showroomsettings/SettingsShowroomEdit.js +++ b/frontend/src/screens/company/settings/showroomsettings/SettingsShowroomEdit.js @@ -105,8 +105,24 @@ export default function SettingsShowroomEdit({ route, navigation }) { if (error.response) { // Request made and server responded console.log(error.response.data); - console.log(error.response.status); - console.log(error.response.headers); + if (error.response.data.hasOwnProperty("address")) { + setAddress({value:address.value, error:error.response.data.address[0]}) + } + if (error.response.data.hasOwnProperty("city")) { + setCity({value:city.value, error:error.response.data.city[0]}) + } + if (error.response.data.hasOwnProperty("country")) { + setCountry({value:country.value, error:error.response.data.country[0]}) + } + if (error.response.data.hasOwnProperty("doorcode")) { + setDoorCode({value:doorCode.value, error:error.response.data.doorcode[0]}) + } + if (error.response.data.hasOwnProperty("start_hours")) { + setStartTime({value:startTime.value, error:error.response.data.start_hours[0]}) + } + if (error.response.data.hasOwnProperty("date_range_start")) { + setStartDate({value:startDate.value, error:error.response.data.date_range_start[0]}) + } } else if (error.request) { // The request was made but no response was received console.log(error.request);