diff --git a/database/copy-prod-db-to-test.sh b/database/copy-prod-db-to-test.sh new file mode 100644 index 0000000..bb8493f --- /dev/null +++ b/database/copy-prod-db-to-test.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +#==================================================================================== +# Script for copying the latest data from the prod database into the local database. +# +# +# REQUIRES: +# sudo apt install postgresql-client +#==================================================================================== + +# exit script on any error +trap 'exit' ERR + + +#------------------------------------------------------------------------------------ +# dump +#------------------------------------------------------------------------------------ +SRC_HOST="localhost" +SRC_PORT="5432" +SRC_USERNAME="supercharge_user" +SRC_DATABASE="postgres" +SRC_SCHEMA="supercharge" +OUT_SQL_DIR="/tmp/migration-dump-prod-$$" + +echo "**** Enter PROD password for ${SRC_USERNAME} on ${SRC_HOST}:${SRC_PORT}" +pg_dump \ + --host=${SRC_HOST} \ + --port=${SRC_PORT} \ + --encoding=UTF-8 \ + --username=${SRC_USERNAME} \ + --dbname=${SRC_DATABASE} \ + --schema=${SRC_SCHEMA} \ + --blobs \ + --format=d \ + --verbose \ + --quote-all-identifiers \ + --jobs=2 \ + --file="${OUT_SQL_DIR}" + + +#------------------------------------------------------------------------------------ +# restore +#------------------------------------------------------------------------------------ +DST_USERNAME="supercharge_user_test" +DST_HOST="localhost" +DST_PORT="5432" +DST_DATABASE="test" +DST_SCHEMA="supercharge" + + +echo "ALTER SCHEMA ${DST_SCHEMA} RENAME TO ${DST_SCHEMA}_$$" | psql --username="${DST_USERNAME}" --host="${DST_HOST}" --port="${DST_PORT}" "${DST_DATABASE}" + +echo "**** Enter password for ${DST_USERNAME} on TARGET database at ${DST_HOST}:${DST_PORT}" +pg_restore \ + --username="${DST_USERNAME}" \ + --host="${DST_HOST}" \ + --dbname="${DST_DATABASE}" \ + --port="${DST_PORT}" \ + --format=d \ + --verbose \ + --jobs=2 \ + "${OUT_SQL_DIR}" + + +echo "done" diff --git a/database/sql/04-tables.sql b/database/sql/04-tables.sql index fbb276e..f85817f 100644 --- a/database/sql/04-tables.sql +++ b/database/sql/04-tables.sql @@ -14,6 +14,7 @@ drop table if exists user_config; drop table if exists user_reset; drop table if exists changelog; drop table if exists site_change; +drop table if exists parking; drop table if exists site; drop table if exists address; drop table if exists country; @@ -40,12 +41,18 @@ alter sequence region_region_id_seq restart with 150; -- ----------------------------------------------------------- create table country ( - country_id serial primary key, - name varchar(100) not null unique, - code varchar(2) not null unique, - region_id int not null, - state_required boolean not null default false, - modified_date timestamptz not null default current_timestamp, + country_id serial primary key, + name varchar(100) not null unique, + code varchar(2) not null unique, + region_id int not null, + state_required boolean not null default false, + modified_date timestamptz not null default current_timestamp, + plugs_tpc boolean not null default true, + plugs_nacs boolean not null default true, + plugs_ccs1 boolean not null default true, + plugs_ccs2 boolean not null default true, + plugs_type2 boolean not null default true, + plugs_gbt boolean not null default true, foreign key (region_id) references region (region_id) on update cascade on delete cascade @@ -75,40 +82,74 @@ create table address ); alter sequence address_address_id_seq restart with 2000000; +-- ----------------------------------------------------------- +-- PARKING - lookup table +-- ----------------------------------------------------------- +create table parking +( + parking_id serial primary key, + name varchar(100) not null, + description text null +); + -- ----------------------------------------------------------- -- SITE -- ----------------------------------------------------------- -create type site_status_type as enum ('CLOSED_PERM','CLOSED_TEMP', 'PERMIT', 'CONSTRUCTION', 'OPEN'); +create type site_status_type as enum ('CLOSED_PERM','CLOSED_TEMP', 'PERMIT', 'CONSTRUCTION', 'OPEN', 'VOTING', 'PLAN', 'EXPANDING'); create table site ( - site_id serial not null, - location_id varchar(300) null default null::character varying, - "name" varchar(100) not null, - status "site_status_type" not null, - opened_date timestamptz null, - hours varchar(100) null default null::character varying, - enabled bool not null default true, - counted bool not null, - address_id int4 not null, - gps_latitude float8 not null, - gps_longitude float8 not null, - elevation_meters int4 not null, - url_discuss varchar(200) null default null::character varying, - stall_count int4 null, - power_kwatt int4 not null default 0, - has_solar_canopy bool not null default false, - has_battery bool not null default false, - developer_notes varchar(1000) null default null::character varying, - modified_date timestamptz not null default now(), - "version" int4 not null default 1, - other_evs bool not null default false, + site_id serial not null, + location_id varchar(300) null default null::character varying, + "name" varchar(100) not null, + status "site_status_type" not null, + opened_date timestamptz null, + hours varchar(100) null default null::character varying, + enabled bool not null default true, + counted bool not null, + address_id int4 not null, + gps_latitude float8 not null, + gps_longitude float8 not null, + elevation_meters int4 not null, + url_discuss varchar(200) null default null::character varying, + stall_count int4 null, + power_kwatt int4 not null default 0, + has_solar_canopy bool not null default false, + has_battery bool not null default false, + developer_notes varchar(1000) null default null::character varying, + modified_date timestamptz not null default now(), + "version" int4 not null default 1, + other_evs bool not null default false, -- TO BE DEPRECATED + stalls_urban int4 null, + stalls_v2 int4 null, + stalls_v3 int4 null, + stalls_v4 int4 null, + stalls_other int4 null, + stalls_accessible int4 null, + stalls_trailer int4 null, + plugs_tpc int4 null, + plugs_nacs int4 null, + plugs_ccs1 int4 null, + plugs_ccs2 int4 null, + plugs_type2 int4 null, + plugs_gbt int4 null, + plugs_other int4 null, + plugs_multi int4 null, + parking_id int4 null, + facility_name varchar(200) null default null::character varying, + facility_hours varchar(100) null default null::character varying, + access_notes varchar(1000) null default null::character varying, + address_notes varchar(1000) null default null::character varying, + plugshare_id int8 null, + osm_id int8 null, constraint address_id_unique unique (address_id), constraint name_unique unique (name), constraint site_id_unique primary key (site_id) ); alter table site add constraint site_address_id_fkey foreign key (address_id) references address(address_id) on delete cascade on update cascade; +alter table site + add constraint site_parking_id_fkey foreign key (parking_id) references parking(parking_id) on delete cascade on update cascade; alter sequence site_site_id_seq restart with 100000; -- ----------------------------------------------------------- diff --git a/database/sql/31-reference-countries.sql b/database/sql/31-reference-countries.sql index 3d4a9a4..66839dd 100644 --- a/database/sql/31-reference-countries.sql +++ b/database/sql/31-reference-countries.sql @@ -62,3 +62,9 @@ INSERT INTO country (country_id,"name",code,region_id,state_required,modified_da INSERT INTO country (country_id,"name",code,region_id,state_required,modified_date) VALUES (160,'Malaysia','MY',102,false,now()); INSERT INTO country (country_id,"name",code,region_id,state_required,modified_date) VALUES (161,'Qatar','QA',102,false,now()); INSERT INTO country (country_id,"name",code,region_id,state_required,modified_date) VALUES (162,'Chile','CL',103,false,now()); + +-- pre-populate valid plug types per country +UPDATE country SET plugs_gbt = false WHERE name != 'China'; +UPDATE country SET plugs_tpc = false, plugs_nacs = false, plugs_ccs1 = false WHERE region_id IN (101, 102) AND name NOT IN ('Japan', 'South Korea', 'Taiwan'); +UPDATE country SET plugs_type2 = false, plugs_ccs2 = false WHERE region_id = 100 OR name IN ('Japan', 'South Korea'); +UPDATE country SET plugs_ccs1 = false WHERE name IN ('Japan', 'Taiwan'); diff --git a/database/sql/32-reference-sites.sql b/database/sql/32-reference-sites.sql index cff4130..a4a3867 100644 --- a/database/sql/32-reference-sites.sql +++ b/database/sql/32-reference-sites.sql @@ -7541,3 +7541,72 @@ COPY "supercharge"."site_change" ("site_id", "user_id", "version", "change_date" -- PostgreSQL database dump complete -- +-- Pre-populate stalls based on max power +UPDATE site SET stalls_urban = stall_count WHERE power_kwatt <= 72; +UPDATE site SET stalls_v2 = stall_count WHERE power_kwatt BETWEEN 73 AND 199; +UPDATE site SET stalls_v3 = stall_count WHERE power_kwatt >= 200; -- a few of these are V4 at the time of release and will have to be updated manually + +-- Pre-populate plugs based on geography, max power, and existing other_evs flag + +-- All stalls in China are GB/T, except Hong Kong and Macau which are CCS2 (with one weird exception in Macau to be updated manually) +UPDATE site s SET plugs_gbt = stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.name = 'China' AND a.state NOT IN ('Hong Kong', 'Macau'); +UPDATE site s SET plugs_ccs2 = stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.name = 'China' AND a.state IN ('Hong Kong', 'Macau'); + +-- All stalls in Jordan are Type2 +UPDATE site s SET plugs_type2 = stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.name = 'Jordan'; + +-- Taiwan is mostly dual-cable CCS2+TPC but some will have to be updated manually +UPDATE site s SET plugs_ccs2 = s.stall_count, plugs_tpc = s.stall_count, plugs_multi = s.stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.name = 'Taiwan'; + +-- North America V2 + Urban, and all stalls in Japan + South Korea, are TPC if they're not already marked open to other EVs +UPDATE site s SET plugs_tpc = s.stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND ((s.power_kwatt < 200 AND c.region_id = 100) OR c.name IN ('Japan', 'South Korea')) AND NOT s.other_evs; + +-- North America + South Korea stalls that are already marked open to other EVs are all MagicDock (TPC+CCS1) +UPDATE site s SET plugs_tpc = s.stall_count, plugs_ccs1 = s.stall_count, plugs_multi = s.stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND (c.region_id = 100 OR c.name = 'South Korea') AND s.other_evs; + +-- North America V3 + V4 stalls are all NACS if they're not already marked open to other EVs +UPDATE site s SET plugs_nacs = s.stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.region_id = 100 AND s.power_kwatt = 250 AND NOT s.other_evs; + +-- Europe V2 stalls are dual-cable CCS2+Type2 +UPDATE site s SET plugs_ccs2 = s.stall_count, plugs_type2 = s.stall_count, plugs_multi = s.stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.region_id = 101 AND s.power_kwatt BETWEEN 73 AND 199; + +-- Presume the rest of the world's V2 stalls have CCS2 plugs +UPDATE site s SET plugs_ccs2 = stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.region_id != 100 AND c.name NOT IN ('China', 'Japan', 'Jordan', 'South Korea', 'Taiwan') +AND NOT (c.region_id = 101 AND s.power_kwatt BETWEEN 73 AND 199); + +-- Pre-populate parking options +INSERT INTO parking (name, description) VALUES + ('Free at all times', 'Unrestricted at all times with no fee to park'), + ('Free with validation', 'No fee to park for the first N minutes of parking with proof of purchase from certain merchants'), + ('Free initially', 'No fee to park for the first N minutes of parking'), + ('Free off-peak', 'No fee to park outside of peak hours/days (e.g. nights, weekends)'), + ('Paid - self parking', 'Fee to park at all times'), + ('Paid - valet parking', 'Fee to park at all times with valet assistance'), + ('Other - see notes', 'Details provided in "Access Notes"'); diff --git a/pom.xml b/pom.xml index 48a80bb..80c20ef 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ info.supercharge.api supercharge.info-api - 5.0.3-SNAPSHOT + 5.1.1-SNAPSHOT diff --git a/service-dao/pom.xml b/service-dao/pom.xml index 00977d5..2739e02 100644 --- a/service-dao/pom.xml +++ b/service-dao/pom.xml @@ -3,7 +3,7 @@ info.supercharge.api supercharge.info-api - 5.0.3-SNAPSHOT + 5.1.1-SNAPSHOT 4.0.0 diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/changelog/ChangeLog.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/changelog/ChangeLog.java index 769800c..08f61cd 100644 --- a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/changelog/ChangeLog.java +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/changelog/ChangeLog.java @@ -1,7 +1,9 @@ package com.redshiftsoft.tesla.dao.changelog; import com.google.common.base.Preconditions; +import com.redshiftsoft.tesla.dao.site.Plugs; import com.redshiftsoft.tesla.dao.site.SiteStatus; +import com.redshiftsoft.tesla.dao.site.Stalls; import java.time.Instant; import java.util.Collections; @@ -35,7 +37,7 @@ public class ChangeLog implements Comparable { // ADD, UPDATE private ChangeType changeType; - // PERMIT, CONSTRUCTION, OPEN + // PERMIT, CONSTRUCTION, OPEN, etc private SiteStatus siteStatus; private SiteStatus prevStatus; @@ -47,7 +49,6 @@ public class ChangeLog implements Comparable { public int getId() { return id; } - public void setId(int id) { this.id = id; } @@ -55,7 +56,6 @@ public void setId(int id) { public Instant getDate() { return date; } - public void setDate(Instant date) { Preconditions.checkArgument(date != null); this.date = date; @@ -64,7 +64,6 @@ public void setDate(Instant date) { public ChangeType getChangeType() { return changeType; } - public void setChangeType(ChangeType changeType) { Preconditions.checkArgument(changeType != null); this.changeType = changeType; @@ -73,7 +72,6 @@ public void setChangeType(ChangeType changeType) { public SiteStatus getSiteStatus() { return siteStatus; } - public void setSiteStatus(SiteStatus siteStatus) { this.siteStatus = siteStatus; } @@ -81,7 +79,6 @@ public void setSiteStatus(SiteStatus siteStatus) { public SiteStatus getPrevStatus() { return prevStatus; } - public void setPrevStatus(SiteStatus prevStatus) { this.prevStatus = prevStatus; } @@ -89,7 +86,6 @@ public void setPrevStatus(SiteStatus prevStatus) { public boolean getNotify() { return notify; } - public void setNotify(boolean notify) { this.notify = notify; } @@ -97,7 +93,6 @@ public void setNotify(boolean notify) { public int getStallCount() { return stallCount; } - public void setStallCount(int stallCount) { this.stallCount = stallCount; } @@ -105,7 +100,6 @@ public void setStallCount(int stallCount) { public int getPowerKilowatt() { return powerKilowatt; } - public void setPowerKilowatt(int powerKilowatt) { this.powerKilowatt = powerKilowatt; } @@ -113,7 +107,6 @@ public void setPowerKilowatt(int powerKilowatt) { public boolean isOtherEVs() { return otherEVs; } - public void setOtherEVs(boolean otherEVs) { this.otherEVs = otherEVs; } @@ -121,7 +114,6 @@ public void setOtherEVs(boolean otherEVs) { public int getSiteId() { return siteId; } - public void setSiteId(int siteId) { this.siteId = siteId; } @@ -129,7 +121,6 @@ public void setSiteId(int siteId) { public Instant getModifiedInstant() { return modifiedInstant; } - public void setModifiedInstant(Instant modifiedInstant) { this.modifiedInstant = modifiedInstant; } @@ -137,7 +128,6 @@ public void setModifiedInstant(Instant modifiedInstant) { public String getSiteName() { return siteName; } - public void setSiteName(String siteName) { this.siteName = siteName; } @@ -145,7 +135,6 @@ public void setSiteName(String siteName) { public int getRegionId() { return regionId; } - public void setRegionId(int regionId) { this.regionId = regionId; } @@ -153,7 +142,6 @@ public void setRegionId(int regionId) { public String getRegionName() { return regionName; } - public void setRegionName(String regionName) { this.regionName = regionName; } @@ -161,7 +149,6 @@ public void setRegionName(String regionName) { public int getCountryId() { return countryId; } - public void setCountryId(int countryId) { this.countryId = countryId; } @@ -169,7 +156,6 @@ public void setCountryId(int countryId) { public String getCountryName() { return countryName; } - public void setCountryName(String countryName) { this.countryName = countryName; } @@ -177,7 +163,6 @@ public void setCountryName(String countryName) { public String getState() { return state; } - public void setState(String state) { this.state = state; } diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Country.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Country.java index 31f3ce0..511cb3e 100644 --- a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Country.java +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Country.java @@ -15,6 +15,13 @@ public class Country { /* Is the state field required for addresses in this country. */ private boolean stateRequired; + private boolean plugTPC; + private boolean plugNACS; + private boolean plugCCS1; + private boolean plugCCS2; + private boolean plugType2; + private boolean plugGBT; + public Country() { } @@ -65,7 +72,6 @@ public String toString() { public int getId() { return id; } - public void setId(int id) { this.id = id; } @@ -73,7 +79,6 @@ public void setId(int id) { public String getName() { return name; } - public void setName(String name) { this.name = name; } @@ -81,7 +86,6 @@ public void setName(String name) { public String getCode() { return code; } - public void setCode(String code) { this.code = code; } @@ -89,7 +93,6 @@ public void setCode(String code) { public int getRegionId() { return regionId; } - public void setRegionId(int regionId) { this.regionId = regionId; } @@ -97,7 +100,6 @@ public void setRegionId(int regionId) { public String getRegionName() { return regionName; } - public void setRegionName(String regionName) { this.regionName = regionName; } @@ -105,8 +107,50 @@ public void setRegionName(String regionName) { public boolean isStateRequired() { return stateRequired; } - public void setStateRequired(boolean stateRequired) { this.stateRequired = stateRequired; } + + public boolean isPlugTPC() { + return plugTPC; + } + public void setPlugTPC(boolean plugTPC) { + this.plugTPC = plugTPC; + } + + public boolean isPlugNACS() { + return plugNACS; + } + public void setPlugNACS(boolean plugNACS) { + this.plugNACS = plugNACS; + } + + public boolean isPlugCCS1() { + return plugCCS1; + } + public void setPlugCCS1(boolean plugCCS1) { + this.plugCCS1 = plugCCS1; + } + + public boolean isPlugCCS2() { + return plugCCS2; + } + public void setPlugCCS2(boolean plugCCS2) { + this.plugCCS2 = plugCCS2; + } + + public boolean isPlugType2() { + return plugType2; + } + public void setPlugType2(boolean plugType2) { + this.plugType2 = plugType2; + } + + public boolean isPlugGBT() { + return plugGBT; + } + public void setPlugGBT(boolean plugGBT) { + this.plugGBT = plugGBT; + } + } diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/CountryRowMapper.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/CountryRowMapper.java index ae68da7..26be111 100644 --- a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/CountryRowMapper.java +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/CountryRowMapper.java @@ -30,6 +30,14 @@ public Country mapRow(ResultSet rs, int rowNum) throws SQLException { country.setRegionId(rs.getInt(c++)); country.setStateRequired(rs.getBoolean(c++)); c++; // modified_date + + country.setPlugTPC(rs.getBoolean(c++)); + country.setPlugNACS(rs.getBoolean(c++)); + country.setPlugCCS1(rs.getBoolean(c++)); + country.setPlugCCS2(rs.getBoolean(c++)); + country.setPlugType2(rs.getBoolean(c++)); + country.setPlugGBT(rs.getBoolean(c++)); + country.setRegionName(rs.getString(c)); return country; } diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Parking.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Parking.java new file mode 100644 index 0000000..98e7ee9 --- /dev/null +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Parking.java @@ -0,0 +1,76 @@ +package com.redshiftsoft.tesla.dao.site; + +import java.util.Arrays; +import java.util.List; + +public class Parking { + + private int parkingId; + private String name; + private String description; + + public Parking() { + } + + public Parking(int parkingId, String name, String description) { + this.parkingId = parkingId; + this.name = name; + this.description = description; + } + + // - - - - - - - - - + // java.lang.Object + // - - - - - - - - - + + private List getIdentityFields() { + return Arrays.asList(parkingId, name); + } + + @Override + public int hashCode() { + return getIdentityFields().hashCode(); + } + + @Override + public boolean equals(Object other) { + return this == other || (other instanceof Parking) && + this.getIdentityFields().equals(((Parking) other).getIdentityFields()); + } + + @Override + public String toString() { + return "Parking{" + + "id=" + parkingId + + ", name='" + name + "'" + + ", description='" + description + "'" + + "}"; + } + + // - - - - - - - - - + // getters/setters + // - - - - - - - - - + + public int getParkingId() { + return parkingId; + } + + public void setParkingId(int parkingId) { + this.parkingId = parkingId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/ParkingDAO.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/ParkingDAO.java new file mode 100644 index 0000000..b729738 --- /dev/null +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/ParkingDAO.java @@ -0,0 +1,46 @@ +package com.redshiftsoft.tesla.dao.site; + +import com.redshiftsoft.tesla.dao.BaseDAO; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.function.Supplier; + +@Component +public class ParkingDAO extends BaseDAO implements Supplier> { + + private static final ParkingRowMapper PARKING_ROW_MAPPER = new ParkingRowMapper(); + + public List getAll() { + return getJdbcTemplate().query(ParkingRowMapper.SELECT_ALL, PARKING_ROW_MAPPER); + } + + @Override + public List get() { + return getAll(); + } + + + public Parking getById(int parkingId) { + return getJdbcTemplate().queryForObject("SELECT * FROM parking WHERE parking_id=?", PARKING_ROW_MAPPER, parkingId); + } + + private static class ParkingRowMapper implements RowMapper { + + private static final String SELECT_ALL = "SELECT * FROM parking ORDER BY parking_id ASC"; + + @Override + public Parking mapRow(ResultSet rs, int rowNum) throws SQLException { + Parking parking = new Parking(); + int c = 1; + parking.setParkingId(rs.getInt(c++)); + parking.setName(rs.getString(c++)); + parking.setDescription(rs.getString(c)); + return parking; + } + } + +} diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Plugs.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Plugs.java new file mode 100644 index 0000000..2969cee --- /dev/null +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Plugs.java @@ -0,0 +1,74 @@ +package com.redshiftsoft.tesla.dao.site; + +public class Plugs { + + private Integer TPC; + private Integer NACS; + private Integer CCS1; + private Integer CCS2; + private Integer Type2; + private Integer GBT; + private Integer Other; + private Integer Multi; + + public Plugs nullIfEmpty() { + return TPC == null && NACS == null && CCS1 == null && CCS2 == null && Type2 == null && GBT == null && Other == null && Multi == null ? null : this; + } + + public Integer getTPC() { + return TPC; + } + public void setTPC(Integer TPC) { + this.TPC = TPC; + } + + public Integer getNACS() { + return NACS; + } + public void setNACS(Integer NACS) { + this.NACS = NACS; + } + + public Integer getCCS1() { + return CCS1; + } + public void setCCS1(Integer CCS1) { + this.CCS1 = CCS1; + } + + public Integer getCCS2() { + return CCS2; + } + public void setCCS2(Integer CCS2) { + this.CCS2 = CCS2; + } + + public Integer getType2() { + return Type2; + } + public void setType2(Integer Type2) { + this.Type2 = Type2; + } + + public Integer getGBT() { + return GBT; + } + public void setGBT(Integer GBT) { + this.GBT = GBT; + } + + public Integer getOther() { + return Other; + } + public void setOther(Integer Other) { + this.Other = Other; + } + + public Integer getMulti() { + return Multi; + } + public void setMulti(Integer Multi) { + this.Multi = Multi; + } + +} diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Site.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Site.java index 1b0d5b8..2503a21 100644 --- a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Site.java +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Site.java @@ -33,6 +33,16 @@ public class Site { private boolean battery; private boolean otherEVs; + private Stalls stalls = new Stalls(); + private Plugs plugs = new Plugs(); + private Integer parkingId; + private String facilityName; + private String facilityHours; + private String accessNotes; + private String addressNotes; + private Long plugshareId; + private Long osmId; + // - - - - - - - - - - - - - - - - - - - - - - - // java.lang.Object // - - - - - - - - - - - - - - - - - - - - - - - @@ -90,7 +100,6 @@ public boolean isTempClosed() { public int getId() { return id; } - public void setId(int id) { this.id = id; } @@ -98,7 +107,6 @@ public void setId(int id) { public String getName() { return name; } - public void setName(String name) { this.name = name; } @@ -106,7 +114,6 @@ public void setName(String name) { public SiteStatus getStatus() { return status; } - public void setStatus(SiteStatus status) { this.status = status; } @@ -114,7 +121,6 @@ public void setStatus(SiteStatus status) { public LocalDate getDateOpened() { return dateOpened; } - public void setDateOpened(LocalDate dateOpened) { this.dateOpened = dateOpened; } @@ -122,7 +128,6 @@ public void setDateOpened(LocalDate dateOpened) { public LocalDateTime getDateModified() { return dateModified; } - public void setDateModified(LocalDateTime dateModified) { this.dateModified = dateModified; } @@ -130,7 +135,6 @@ public void setDateModified(LocalDateTime dateModified) { public Address getAddress() { return address; } - public void setAddress(Address address) { this.address = address; } @@ -138,7 +142,6 @@ public void setAddress(Address address) { public SiteGPS getGps() { return gps; } - public void setGps(SiteGPS gps) { this.gps = gps; } @@ -146,7 +149,6 @@ public void setGps(SiteGPS gps) { public Integer getElevationMeters() { return elevationMeters; } - public void setElevationMeters(Integer elevationMeters) { this.elevationMeters = elevationMeters; } @@ -154,7 +156,6 @@ public void setElevationMeters(Integer elevationMeters) { public String getUrlDiscuss() { return urlDiscuss; } - public void setUrlDiscuss(String urlDiscuss) { this.urlDiscuss = urlDiscuss; } @@ -162,7 +163,6 @@ public void setUrlDiscuss(String urlDiscuss) { public int getStallCount() { return stallCount; } - public void setStallCount(int stallCount) { this.stallCount = stallCount; } @@ -170,7 +170,6 @@ public void setStallCount(int stallCount) { public boolean isCounted() { return counted; } - public void setCounted(boolean counted) { this.counted = counted; } @@ -178,7 +177,6 @@ public void setCounted(boolean counted) { public boolean isEnabled() { return enabled; } - public void setEnabled(boolean enabled) { this.enabled = enabled; } @@ -186,7 +184,6 @@ public void setEnabled(boolean enabled) { public String getHours() { return hours; } - public void setHours(String hours) { this.hours = hours; } @@ -194,7 +191,6 @@ public void setHours(String hours) { public String getLocationId() { return locationId; } - public void setLocationId(String locationId) { this.locationId = locationId; } @@ -202,7 +198,6 @@ public void setLocationId(String locationId) { public int getPowerKilowatt() { return powerKilowatt; } - public void setPowerKilowatt(int powerKilowatt) { this.powerKilowatt = powerKilowatt; } @@ -210,7 +205,6 @@ public void setPowerKilowatt(int powerKilowatt) { public boolean isSolarCanopy() { return solarCanopy; } - public void setSolarCanopy(boolean solarCanopy) { this.solarCanopy = solarCanopy; } @@ -218,7 +212,6 @@ public void setSolarCanopy(boolean solarCanopy) { public boolean isBattery() { return battery; } - public void setBattery(boolean battery) { this.battery = battery; } @@ -226,7 +219,6 @@ public void setBattery(boolean battery) { public String getDeveloperNotes() { return developerNotes; } - public void setDeveloperNotes(String developerNotes) { this.developerNotes = developerNotes; } @@ -234,7 +226,6 @@ public void setDeveloperNotes(String developerNotes) { public int getVersion() { return version; } - public void setVersion(int version) { this.version = version; } @@ -242,8 +233,71 @@ public void setVersion(int version) { public boolean isOtherEVs() { return otherEVs; } - public void setOtherEVs(boolean otherEVs) { this.otherEVs = otherEVs; } + + public Stalls getStalls() { + return stalls; + } + public void setStalls(Stalls stalls) { + this.stalls = stalls; + } + + public Plugs getPlugs() { + return plugs; + } + public void setPlugs(Plugs plugs) { + this.plugs = plugs; + } + + public Integer getParkingId() { + return parkingId; + } + public void setParkingId(Integer parkingId) { + this.parkingId = parkingId; + } + + public String getFacilityName() { + return facilityName; + } + public void setFacilityName(String facilityName) { + this.facilityName = facilityName; + } + + public String getFacilityHours() { + return facilityHours; + } + public void setFacilityHours(String facilityHours) { + this.facilityHours = facilityHours; + } + + public String getAccessNotes() { + return accessNotes; + } + public void setAccessNotes(String accessNotes) { + this.accessNotes = accessNotes; + } + + public String getAddressNotes() { + return addressNotes; + } + public void setAddressNotes(String addressNotes) { + this.addressNotes = addressNotes; + } + + public Long getPlugshareId() { + return plugshareId; + } + public void setPlugshareId(Long plugshareId) { + this.plugshareId = plugshareId; + } + + public Long getOsmId() { + return osmId; + } + public void setOsmId(Long osmId) { + this.osmId = osmId; + } + } diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteInsertStatementCreator.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteInsertStatementCreator.java index 5419d84..b66af94 100644 --- a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteInsertStatementCreator.java +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteInsertStatementCreator.java @@ -2,16 +2,18 @@ import com.redshiftsoft.tesla.dao.LocalDateUtil; import org.springframework.jdbc.core.PreparedStatementCreator; +import org.springframework.jdbc.core.SqlTypeValue; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.sql.Types; import static com.redshiftsoft.tesla.dao.DAOTools.string; public class SiteInsertStatementCreator implements PreparedStatementCreator { - private static final String SQL = "insert into site values (DEFAULT,?,?,?::SITE_STATUS_TYPE,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),?,?)"; + private static final String SQL = "insert into site values (DEFAULT,?,?,?::SITE_STATUS_TYPE,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; private final Site site; public SiteInsertStatementCreator(Site site) { @@ -50,10 +52,40 @@ public PreparedStatement createPreparedStatement(Connection con) throws SQLExcep stat.setBoolean(c++, site.isBattery()); stat.setString(c++, string(site.getDeveloperNotes())); stat.setInt(c++, site.getVersion()); - stat.setBoolean(c, site.isOtherEVs()); + stat.setBoolean(c++, site.isOtherEVs()); + + // use setObject() instead of type-specific setX() for better null handling + Stalls stalls = site.getStalls(); + if (stalls == null) stalls = new Stalls(); + stat.setObject(c++, stalls.getUrban(), Types.INTEGER); + stat.setObject(c++, stalls.getV2(), Types.INTEGER); + stat.setObject(c++, stalls.getV3(), Types.INTEGER); + stat.setObject(c++, stalls.getV4(), Types.INTEGER); + stat.setObject(c++, stalls.getOther(), Types.INTEGER); + stat.setObject(c++, stalls.getAccessible(), Types.INTEGER); + stat.setObject(c++, stalls.getTrailerFriendly(), Types.INTEGER); + + Plugs plugs = site.getPlugs(); + if (plugs == null) plugs = new Plugs(); + + stat.setObject(c++, plugs.getTPC(), Types.INTEGER); + stat.setObject(c++, plugs.getNACS(), Types.INTEGER); + stat.setObject(c++, plugs.getCCS1(), Types.INTEGER); + stat.setObject(c++, plugs.getCCS2(), Types.INTEGER); + stat.setObject(c++, plugs.getType2(), Types.INTEGER); + stat.setObject(c++, plugs.getGBT(), Types.INTEGER); + stat.setObject(c++, plugs.getOther(), Types.INTEGER); + stat.setObject(c++, plugs.getMulti(), Types.INTEGER); + + stat.setObject(c++, site.getParkingId(), Types.INTEGER); + stat.setString(c++, string(site.getFacilityName())); + stat.setString(c++, string(site.getFacilityHours())); + stat.setString(c++, string(site.getAccessNotes())); + stat.setString(c++, string(site.getAddressNotes())); + stat.setObject(c++, site.getPlugshareId(), Types.BIGINT); + stat.setObject(c++, site.getOsmId(), Types.BIGINT); return stat; } - } diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteRowMapper.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteRowMapper.java index 9273036..6d28923 100644 --- a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteRowMapper.java +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteRowMapper.java @@ -52,6 +52,36 @@ public Site mapRow(ResultSet rs, int rowNum) throws SQLException { site.setVersion(rs.getInt(c++)); site.setOtherEVs(rs.getBoolean(c++)); + // Used typed getObject() instead of specific getX() for better null handling + Stalls stalls = new Stalls(); + stalls.setUrban(rs.getObject(c++, Integer.class)); + stalls.setV2(rs.getObject(c++, Integer.class)); + stalls.setV3(rs.getObject(c++, Integer.class)); + stalls.setV4(rs.getObject(c++, Integer.class)); + stalls.setOther(rs.getObject(c++, Integer.class)); + stalls.setAccessible(rs.getObject(c++, Integer.class)); + stalls.setTrailerFriendly(rs.getObject(c++, Integer.class)); + site.setStalls(stalls.nullIfEmpty()); + + Plugs plugs = new Plugs(); + plugs.setTPC(rs.getObject(c++, Integer.class)); + plugs.setNACS(rs.getObject(c++, Integer.class)); + plugs.setCCS1(rs.getObject(c++, Integer.class)); + plugs.setCCS2(rs.getObject(c++, Integer.class)); + plugs.setType2(rs.getObject(c++, Integer.class)); + plugs.setGBT(rs.getObject(c++, Integer.class)); + plugs.setOther(rs.getObject(c++, Integer.class)); + plugs.setMulti(rs.getObject(c++, Integer.class)); + site.setPlugs(plugs.nullIfEmpty()); + + site.setParkingId(rs.getObject(c++, Integer.class)); + site.setFacilityName(rs.getString(c++)); + site.setFacilityHours(rs.getString(c++)); + site.setAccessNotes(rs.getString(c++)); + site.setAddressNotes(rs.getString(c++)); + site.setPlugshareId(rs.getObject(c++, Long.class)); + site.setOsmId(rs.getObject(c++, Long.class)); + site.setAddress(new AddressRowMapper(c).mapRow(rs, rowNum)); return site; diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteStatus.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteStatus.java index 6237283..ef60bc9 100644 --- a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteStatus.java +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteStatus.java @@ -6,7 +6,10 @@ public enum SiteStatus { CLOSED_TEMP, PERMIT, CONSTRUCTION, - OPEN; + OPEN, + VOTING, + PLAN, + EXPANDING; public boolean isClosedTemp() { return CLOSED_TEMP == this; @@ -27,4 +30,16 @@ public boolean isConstruction() { public boolean isOpen() { return OPEN == this; } + + public boolean isVoting() { + return VOTING == this; + } + + public boolean isPlan() { + return PLAN == this; + } + + public boolean isExpanding() { + return EXPANDING == this; + } } diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteUpdateStatementCreator.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteUpdateStatementCreator.java index fe0c521..c97fb43 100644 --- a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteUpdateStatementCreator.java +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/SiteUpdateStatementCreator.java @@ -6,6 +6,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.sql.Types; import static com.redshiftsoft.tesla.dao.DAOTools.string; @@ -14,7 +15,10 @@ public class SiteUpdateStatementCreator implements PreparedStatementCreator { private static final String SQL = "update site " + "set location_id=?,name=?,status=?::SITE_STATUS_TYPE,opened_date=?,hours=?,enabled=?,counted=?," + "gps_latitude=?,gps_longitude=?,elevation_meters=?,url_discuss=?,stall_count=?,power_kwatt=?," + - "has_solar_canopy=?,has_battery=?,developer_notes=?,modified_date=now(),version=version+1,other_evs=?" + + "has_solar_canopy=?,has_battery=?,developer_notes=?,modified_date=now(),version=version+1,other_evs=?," + + "stalls_urban=?,stalls_v2=?,stalls_v3=?,stalls_v4=?,stalls_other=?,stalls_accessible=?,stalls_trailer=?," + + "plugs_tpc=?,plugs_nacs=?,plugs_ccs1=?,plugs_ccs2=?,plugs_type2=?,plugs_gbt=?,plugs_other=?,plugs_multi=?," + + "parking_id=?,facility_name=?,facility_hours=?,access_notes=?,address_notes=?,plugshare_id=?,osm_id=?" + " where site_id=?"; private final Site site; @@ -54,6 +58,36 @@ public PreparedStatement createPreparedStatement(Connection con) throws SQLExcep stat.setString(c++, string(site.getDeveloperNotes())); stat.setBoolean(c++, site.isOtherEVs()); + // use setObject() instead of type-specific setX() for better null handling + Stalls stalls = site.getStalls(); + if (stalls == null) stalls = new Stalls(); + stat.setObject(c++, stalls.getUrban(), Types.INTEGER); + stat.setObject(c++, stalls.getV2(), Types.INTEGER); + stat.setObject(c++, stalls.getV3(), Types.INTEGER); + stat.setObject(c++, stalls.getV4(), Types.INTEGER); + stat.setObject(c++, stalls.getOther(), Types.INTEGER); + stat.setObject(c++, stalls.getAccessible(), Types.INTEGER); + stat.setObject(c++, stalls.getTrailerFriendly(), Types.INTEGER); + + Plugs plugs = site.getPlugs(); + if (plugs == null) plugs = new Plugs(); + stat.setObject(c++, plugs.getTPC(), Types.INTEGER); + stat.setObject(c++, plugs.getNACS(), Types.INTEGER); + stat.setObject(c++, plugs.getCCS1(), Types.INTEGER); + stat.setObject(c++, plugs.getCCS2(), Types.INTEGER); + stat.setObject(c++, plugs.getType2(), Types.INTEGER); + stat.setObject(c++, plugs.getGBT(), Types.INTEGER); + stat.setObject(c++, plugs.getOther(), Types.INTEGER); + stat.setObject(c++, plugs.getMulti(), Types.INTEGER); + + stat.setObject(c++, site.getParkingId(), Types.INTEGER); + stat.setString(c++, string(site.getFacilityName())); + stat.setString(c++, string(site.getFacilityHours())); + stat.setString(c++, string(site.getAccessNotes())); + stat.setString(c++, string(site.getAddressNotes())); + stat.setObject(c++, site.getPlugshareId(), Types.BIGINT); + stat.setObject(c++, site.getOsmId(), Types.BIGINT); + stat.setInt(c, site.getId()); return stat; diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Stalls.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Stalls.java new file mode 100644 index 0000000..b0305da --- /dev/null +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/site/Stalls.java @@ -0,0 +1,66 @@ +package com.redshiftsoft.tesla.dao.site; + +public class Stalls { + + private Integer urban; + private Integer v2; + private Integer v3; + private Integer v4; + private Integer other; + private Integer accessible; + private Integer trailerFriendly; + + public Stalls nullIfEmpty() { + return urban == null && v2 == null && v3 == null && v4 == null && other == null && accessible == null && trailerFriendly == null ? null : this; + } + + public Integer getUrban() { + return urban; + } + public void setUrban(Integer urban) { + this.urban = urban; + } + + public Integer getV2() { + return v2; + } + public void setV2(Integer v2) { + this.v2 = v2; + } + + public Integer getV3() { + return v3; + } + public void setV3(Integer v3) { + this.v3 = v3; + } + + public Integer getV4() { + return v4; + } + public void setV4(Integer v4) { + this.v4 = v4; + } + + public Integer getOther() { + return other; + } + public void setOther(Integer other) { + this.other = other; + } + + public Integer getAccessible() { + return accessible; + } + public void setAccessible(Integer accessible) { + this.accessible = accessible; + } + + public Integer getTrailerFriendly() { + return trailerFriendly; + } + public void setTrailerFriendly(Integer trailerFriendly) { + this.trailerFriendly = trailerFriendly; + } + +} diff --git a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/validation/Validations.java b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/validation/Validations.java index 04b177f..d09ba1f 100644 --- a/service-dao/src/main/java/com/redshiftsoft/tesla/dao/validation/Validations.java +++ b/service-dao/src/main/java/com/redshiftsoft/tesla/dao/validation/Validations.java @@ -17,14 +17,14 @@ public static Collection getValidations() { new Validation(SUPERCHARGER, "open date consistent with status", "" + "SELECT * " + "FROM site " + - "WHERE (status = 'OPEN' AND opened_date IS NULL) OR (status != 'OPEN' AND opened_date IS NOT NULL)") + "WHERE (status IN ('OPEN', 'EXPANDING') AND opened_date IS NULL) OR (status NOT IN ('OPEN', 'EXPANDING') AND opened_date IS NOT NULL)") ); validationMap.add( new Validation(SUPERCHARGER, "Tesla location id is not null for OPEN site", "" + "SELECT * " + "FROM site " + - "WHERE status = 'OPEN' AND location_id IS NULL") + "WHERE status IN ('OPEN', 'EXPANDING') AND location_id IS NULL") ); validationMap.add( @@ -34,10 +34,10 @@ public static Collection getValidations() { ); validationMap.add( - new Validation(SUPERCHARGER, "stall count non zero for OPEN sites", "" + + new Validation(SUPERCHARGER, "stall count non zero for OPEN/EXPANDING sites", "" + "SELECT * " + "FROM site " + - "WHERE status = 'OPEN' AND (stall_count IS NULL OR stall_count = 0)") + "WHERE status IN ('OPEN', 'EXPANDING') AND (stall_count IS NULL OR stall_count = 0)") ); validationMap.add( @@ -47,6 +47,43 @@ public static Collection getValidations() { "GROUP BY name HAVING count(*) > 1") ); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | STALLS + + validationMap.add( + new Validation(SUPERCHARGER, "total stall count not equal to sum of individual stall types", "" + + "SELECT * " + + "FROM site " + + "WHERE stall_count != COALESCE(stalls_urban, 0) + COALESCE(stalls_v2, 0) + COALESCE(stalls_v3, 0) + COALESCE(stalls_v4, 0) + COALESCE(stalls_other, 0)") + ); + + validationMap.add( + new Validation(SUPERCHARGER, "accessible and/or trailer-friendly stall counts exceed total", "" + + "SELECT * " + + "FROM site " + + "WHERE COALESCE(stalls_accessible, 0) > stall_count " + + "OR COALESCE(stalls_trailer, 0) > stall_count") + ); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | PLUGS + + validationMap.add( + new Validation(SUPERCHARGER, "total stall count not equal to sum of individual plug counts (with no multi-plug stalls)", "" + + "SELECT * " + + "FROM site " + + "WHERE COALESCE(plugs_multi, 0) = 0 AND stall_count != " + + "COALESCE(plugs_tpc, 0) + COALESCE(plugs_nacs, 0) + COALESCE(plugs_ccs1, 0) + COALESCE(plugs_ccs2, 0) + " + + "COALESCE(plugs_type2, 0) + COALESCE(plugs_gbt, 0) + COALESCE(plugs_other, 0)") + ); + + validationMap.add( + new Validation(SUPERCHARGER, "total stall count more than expected (with multi-plug stalls)", "" + + "SELECT * " + + "FROM site " + + "WHERE COALESCE(plugs_multi, 0) > 0 AND stall_count > " + + "COALESCE(plugs_tpc, 0) + COALESCE(plugs_nacs, 0) + COALESCE(plugs_ccs1, 0) + COALESCE(plugs_ccs2, 0) + " + + "COALESCE(plugs_type2, 0) + COALESCE(plugs_gbt, 0) + COALESCE(plugs_other, 0) - plugs_multi") + ); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ADDRESS validationMap.add( diff --git a/service-dao/src/main/sql/schema-changes.sql b/service-dao/src/main/sql/schema-changes.sql index ca153cc..f292bf3 100644 --- a/service-dao/src/main/sql/schema-changes.sql +++ b/service-dao/src/main/sql/schema-changes.sql @@ -1,4 +1,126 @@ -- ============================================================================ -- File for SQL that will change the schema. Clear this file after prod deploy. -- ============================================================================ -CREATE INDEX changelog_site_id_change_date ON changelog (site_id, change_date); +alter type site_status_type add value 'VOTING'; +alter type site_status_type add value 'PLAN'; +alter type site_status_type add value 'EXPANDING'; + +create table parking +( + parking_id serial primary key, + name varchar(100) not null, + description text null +); +-- not sure why this needs to be done separately/explicitly, considering the contents of 03-permissions.sql +grant all privileges on parking to supercharge_user; + +alter table site + add column stalls_urban int4 null, + add column stalls_v2 int4 null, + add column stalls_v3 int4 null, + add column stalls_v4 int4 null, + add column stalls_other int4 null, + add column stalls_accessible int4 null, + add column stalls_trailer int4 null, + add column plugs_tpc int4 null, + add column plugs_nacs int4 null, + add column plugs_ccs1 int4 null, + add column plugs_ccs2 int4 null, + add column plugs_type2 int4 null, + add column plugs_gbt int4 null, + add column plugs_other int4 null, + add column plugs_multi int4 null, + add column parking_id int4 null, + add column facility_name varchar(200) null default null::character varying, + add column facility_hours varchar(100) null default null::character varying, + add column access_notes varchar(1000) null default null::character varying, + add column address_notes varchar(1000) null default null::character varying, + add column plugshare_id int8 null, + add column osm_id int8 null; + +alter table site + add constraint site_parking_id_fkey foreign key (parking_id) references parking(parking_id) on delete cascade on update cascade; + +alter table country + add column plugs_tpc boolean not null default true, + add column plugs_nacs boolean not null default true, + add column plugs_ccs1 boolean not null default true, + add column plugs_ccs2 boolean not null default true, + add column plugs_type2 boolean not null default true, + add column plugs_gbt boolean not null default true; + +-- pre-populate valid plug types per country +UPDATE country SET plugs_gbt = false WHERE name != 'China'; +UPDATE country SET plugs_tpc = false, plugs_nacs = false, plugs_ccs1 = false WHERE region_id IN (101, 102) AND name NOT IN ('Japan', 'South Korea', 'Taiwan'); +UPDATE country SET plugs_type2 = false, plugs_ccs2 = false WHERE region_id = 100 OR name IN ('Japan', 'South Korea'); +UPDATE country SET plugs_ccs1 = false WHERE name IN ('Japan', 'Taiwan'); + +-- Pre-populate stalls based on max power +UPDATE site SET stalls_urban = stall_count WHERE power_kwatt <= 72; +UPDATE site SET stalls_v2 = stall_count WHERE power_kwatt BETWEEN 73 AND 199; +UPDATE site SET stalls_v3 = stall_count WHERE power_kwatt >= 200; -- a few of these are V4 at the time of release and will have to be updated manually + +-- Pre-populate plugs based on geography, max power, and existing other_evs flag + +-- All stalls in China are GB/T, except Hong Kong and Macau which are CCS2 (with one weird exception in Macau to be updated manually) +UPDATE site s SET plugs_gbt = stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.name = 'China' AND a.state NOT IN ('Hong Kong', 'Macau'); +UPDATE site s SET plugs_ccs2 = stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.name = 'China' AND a.state IN ('Hong Kong', 'Macau'); + +-- All stalls in Jordan are Type2 +UPDATE site s SET plugs_type2 = stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.name = 'Jordan'; + +-- Taiwan is mostly dual-cable CCS2+TPC but some will have to be updated manually +UPDATE site s SET plugs_ccs2 = s.stall_count, plugs_tpc = s.stall_count, plugs_multi = s.stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.name = 'Taiwan'; + +-- North America V2 + Urban, and all stalls in Japan + South Korea, are TPC if they're not already marked open to other EVs +UPDATE site s SET plugs_tpc = s.stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND ((s.power_kwatt < 200 AND c.region_id = 100) OR c.name IN ('Japan', 'South Korea')) AND NOT s.other_evs; + +-- North America + South Korea stalls that are already marked open to other EVs are all MagicDock (NACS+CCS1) +UPDATE site s SET plugs_nacs = s.stall_count, plugs_ccs1 = s.stall_count, plugs_multi = s.stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND (c.region_id = 100 OR c.name = 'South Korea') AND s.other_evs; + +-- North America V3 + V4 stalls are all NACS if they're not already marked open to other EVs +UPDATE site s SET plugs_nacs = s.stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.region_id = 100 AND s.power_kwatt = 250 AND NOT s.other_evs; + +-- Europe V2 stalls are dual-cable CCS2+Type2 +UPDATE site s SET plugs_ccs2 = s.stall_count, plugs_type2 = s.stall_count, plugs_multi = s.stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.region_id = 101 AND s.power_kwatt BETWEEN 73 AND 199; + +-- Presume the rest of the world's V2 stalls have CCS2 plugs +UPDATE site s SET plugs_ccs2 = stall_count +FROM address a, country c +WHERE s.address_id = a.address_id AND a.country_id = c.country_id +AND c.region_id != 100 AND c.name NOT IN ('China', 'Japan', 'Jordan', 'South Korea', 'Taiwan') +AND NOT (c.region_id = 101 AND s.power_kwatt BETWEEN 73 AND 199); + +-- Pre-populate parking options +INSERT INTO parking (name, description) VALUES + ('Free at all times', 'Unrestricted at all times with no fee to park'), + ('Free with validation', 'No fee to park for the first N minutes of parking with proof of purchase from certain merchants'), + ('Free initially', 'No fee to park for the first N minutes of parking'), + ('Free off-peak', 'No fee to park outside of peak hours/days (e.g. nights, weekends)'), + ('Paid - self parking', 'Fee to park at all times'), + ('Paid - valet parking', 'Fee to park at all times with valet assistance'), + ('Other - see notes', 'Details provided in "Access Notes"'); diff --git a/service-dao/src/test/java/com/redshiftsoft/tesla/dao/validation/ValidationDAO_UT.java b/service-dao/src/test/java/com/redshiftsoft/tesla/dao/validation/ValidationDAO_UT.java index 7b54247..c52adba 100644 --- a/service-dao/src/test/java/com/redshiftsoft/tesla/dao/validation/ValidationDAO_UT.java +++ b/service-dao/src/test/java/com/redshiftsoft/tesla/dao/validation/ValidationDAO_UT.java @@ -25,6 +25,6 @@ public class ValidationDAO_UT { public void doValidations() { Collection results = validationDAO.doValidations(); - assertEquals(17, results.size()); + assertEquals(21, results.size()); } } diff --git a/service-war/pom.xml b/service-war/pom.xml index 8a4f5c9..bc39d75 100644 --- a/service-war/pom.xml +++ b/service-war/pom.xml @@ -3,7 +3,7 @@ info.supercharge.api supercharge.info-api - 5.0.3-SNAPSHOT + 5.1.1-SNAPSHOT 4.0.0 diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/country/CountryDTO.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/country/CountryDTO.java index d5eb4ae..3f6868c 100644 --- a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/country/CountryDTO.java +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/country/CountryDTO.java @@ -14,10 +14,16 @@ public class CountryDTO { private String region; private int regionId; + private boolean plugTPC; + private boolean plugNACS; + private boolean plugCCS1; + private boolean plugCCS2; + private boolean plugType2; + private boolean plugGBT; + public int getId() { return id; } - public void setId(int id) { this.id = id; } @@ -25,7 +31,6 @@ public void setId(int id) { public String getName() { return name; } - public void setName(String name) { this.name = name; } @@ -33,7 +38,6 @@ public void setName(String name) { public String getCode() { return code; } - public void setCode(String code) { this.code = code; } @@ -41,7 +45,6 @@ public void setCode(String code) { public String getRegion() { return region; } - public void setRegion(String region) { this.region = region; } @@ -49,8 +52,50 @@ public void setRegion(String region) { public int getRegionId() { return regionId; } - public void setRegionId(int regionId) { this.regionId = regionId; } + + public boolean isPlugTPC() { + return plugTPC; + } + public void setPlugTPC(boolean plugTPC) { + this.plugTPC = plugTPC; + } + + public boolean isPlugNACS() { + return plugNACS; + } + public void setPlugNACS(boolean plugNACS) { + this.plugNACS = plugNACS; + } + + public boolean isPlugCCS1() { + return plugCCS1; + } + public void setPlugCCS1(boolean plugCCS1) { + this.plugCCS1 = plugCCS1; + } + + public boolean isPlugCCS2() { + return plugCCS2; + } + public void setPlugCCS2(boolean plugCCS2) { + this.plugCCS2 = plugCCS2; + } + + public boolean isPlugType2() { + return plugType2; + } + public void setPlugType2(boolean plugType2) { + this.plugType2 = plugType2; + } + + public boolean isPlugGBT() { + return plugGBT; + } + public void setPlugGBT(boolean plugGBT) { + this.plugGBT = plugGBT; + } + } \ No newline at end of file diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/country/CountryDTOFunction.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/country/CountryDTOFunction.java index c8ff5f1..ba4f66f 100644 --- a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/country/CountryDTOFunction.java +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/country/CountryDTOFunction.java @@ -15,7 +15,13 @@ public CountryDTO apply(Country country) { countryDTO.setCode(country.getCode()); countryDTO.setRegionId(country.getRegionId()); countryDTO.setRegion(country.getRegionName()); - + countryDTO.setPlugTPC(country.isPlugTPC()); + countryDTO.setPlugNACS(country.isPlugNACS()); + countryDTO.setPlugCCS1(country.isPlugCCS1()); + countryDTO.setPlugCCS2(country.isPlugCCS2()); + countryDTO.setPlugType2(country.isPlugType2()); + countryDTO.setPlugGBT(country.isPlugGBT()); + return countryDTO; } diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/parking/ParkingController.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/parking/ParkingController.java new file mode 100644 index 0000000..ac113ff --- /dev/null +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/parking/ParkingController.java @@ -0,0 +1,37 @@ +package com.redshiftsoft.tesla.web.mvc.parking; + +import com.redshiftsoft.tesla.dao.dbinfo.DBInfoDAO; +import com.redshiftsoft.tesla.dao.site.Parking; +import com.redshiftsoft.tesla.dao.site.ParkingDAO; +import com.redshiftsoft.tesla.web.mvc.CachingHandler; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.List; + +@Controller +public class ParkingController { + + @Resource + private ParkingDAO parkingDAO; + @Resource + private DBInfoDAO dbInfoDAO; + + private CachingHandler cachingHandler; + + @PostConstruct + public void postConstruct() { + cachingHandler = new CachingHandler<>(dbInfoDAO, "parking", parkingDAO); + } + + @RequestMapping(method = RequestMethod.GET, value = "/parking") + @ResponseBody + public List parking() { + return cachingHandler.getValues(); + } + +} diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/PlugsDTO.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/PlugsDTO.java new file mode 100644 index 0000000..bca36c3 --- /dev/null +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/PlugsDTO.java @@ -0,0 +1,91 @@ +package com.redshiftsoft.tesla.web.mvc.site; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class PlugsDTO { + + private Integer TPC; + private Integer NACS; + private Integer CCS1; + private Integer CCS2; + private Integer Type2; + private Integer GBT; + private Integer Other; + private Integer Multi; + + public PlugsDTO nullIfEmpty() { + return TPC == null && NACS == null && CCS1 == null && CCS2 == null && Type2 == null && GBT == null && Other == null && Multi == null ? null : this; + } + + @JsonIgnore + public int getTotal() { + int total = 0; + if (TPC != null) total += TPC; + if (NACS != null) total += NACS; + if (CCS1 != null) total += CCS1; + if (CCS2 != null) total += CCS2; + if (Type2 != null) total += Type2; + if (GBT != null) total += GBT; + if (Other != null) total += Other; + return total; + } + + public Integer getTPC() { + return TPC; + } + public void setTPC(Integer TPC) { + this.TPC = TPC; + } + + public Integer getNACS() { + return NACS; + } + public void setNACS(Integer NACS) { + this.NACS = NACS; + } + + public Integer getCCS1() { + return CCS1; + } + public void setCCS1(Integer CCS1) { + this.CCS1 = CCS1; + } + + public Integer getCCS2() { + return CCS2; + } + public void setCCS2(Integer CCS2) { + this.CCS2 = CCS2; + } + + public Integer getType2() { + return Type2; + } + public void setType2(Integer Type2) { + this.Type2 = Type2; + } + + public Integer getGBT() { + return GBT; + } + public void setGBT(Integer GBT) { + this.GBT = GBT; + } + + public Integer getOther() { + return Other; + } + public void setOther(Integer Other) { + this.Other = Other; + } + + public Integer getMulti() { + return Multi; + } + public void setMulti(Integer Multi) { + this.Multi = Multi; + } + +} diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/PlugsDTOFunctions.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/PlugsDTOFunctions.java new file mode 100644 index 0000000..0828222 --- /dev/null +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/PlugsDTOFunctions.java @@ -0,0 +1,62 @@ +package com.redshiftsoft.tesla.web.mvc.site; + +import com.redshiftsoft.tesla.dao.site.Plugs; + +import java.util.function.Function; + +public class PlugsDTOFunctions { + + private static final PlugsFunction PLUGS_FUNCTION = new PlugsFunction(); + private static final PlugsDTOFunction PLUGS_DTO_FUNCTION = new PlugsDTOFunction(); + + public static Plugs transform(PlugsDTO plugsDTO) { + return PLUGS_FUNCTION.apply(plugsDTO); + } + + public static PlugsDTO transform(Plugs plugs) { + return PLUGS_DTO_FUNCTION.apply(plugs); + } + + private static class PlugsDTOFunction implements Function { + + @Override + public PlugsDTO apply(Plugs plugs) { + if (plugs == null) return null; + + PlugsDTO plugsDTO = new PlugsDTO(); + + plugsDTO.setTPC(plugs.getTPC()); + plugsDTO.setNACS(plugs.getNACS()); + plugsDTO.setCCS1(plugs.getCCS1()); + plugsDTO.setCCS2(plugs.getCCS2()); + plugsDTO.setType2(plugs.getType2()); + plugsDTO.setGBT(plugs.getGBT()); + plugsDTO.setOther(plugs.getOther()); + plugsDTO.setMulti(plugs.getMulti()); + + return plugsDTO.nullIfEmpty(); + } + } + + private static class PlugsFunction implements Function { + + @Override + public Plugs apply(PlugsDTO plugsDTO) { + if (plugsDTO == null) return null; + + Plugs plugs = new Plugs(); + + plugs.setTPC(plugsDTO.getTPC()); + plugs.setNACS(plugsDTO.getNACS()); + plugs.setCCS1(plugsDTO.getCCS1()); + plugs.setCCS2(plugsDTO.getCCS2()); + plugs.setType2(plugsDTO.getType2()); + plugs.setGBT(plugsDTO.getGBT()); + plugs.setOther(plugsDTO.getOther()); + plugs.setMulti(plugsDTO.getMulti()); + + return plugs.nullIfEmpty(); + } + } + +} \ No newline at end of file diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/SiteDTO.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/SiteDTO.java index 037663d..68b1a97 100644 --- a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/SiteDTO.java +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/SiteDTO.java @@ -40,7 +40,7 @@ public class SiteDTO { private boolean enabled; private Integer elevationMeters; - // /* Power in kW */ + /* Power in kW */ private int powerKilowatt; private boolean solarCanopy; private boolean battery; @@ -51,6 +51,12 @@ public class SiteDTO { /* True if there is one, false otherwise */ private boolean urlDiscuss; + private StallsDTO stalls = null; + private PlugsDTO plugs = null; + + private Integer parkingId; + private String facilityName, facilityHours, accessNotes, addressNotes; + private Long plugshareId, osmId; // - - - - - - - - - - - - - - - - - - - - - - - // java.lang.Object @@ -77,7 +83,6 @@ private List getIdentityFields() { public int getId() { return id; } - public void setId(int id) { this.id = id; } @@ -85,7 +90,6 @@ public void setId(int id) { public String getName() { return name; } - public void setName(String name) { this.name = name; } @@ -93,7 +97,6 @@ public void setName(String name) { public SiteStatus getStatus() { return status; } - public void setStatus(SiteStatus status) { this.status = status; } @@ -103,7 +106,6 @@ public void setStatus(SiteStatus status) { public LocalDate getDateOpened() { return dateOpened; } - public void setDateOpened(LocalDate dateOpened) { this.dateOpened = dateOpened; } @@ -111,7 +113,6 @@ public void setDateOpened(LocalDate dateOpened) { public AddressDTO getAddress() { return address; } - public void setAddress(AddressDTO address) { this.address = address; } @@ -119,7 +120,6 @@ public void setAddress(AddressDTO address) { public SiteGPS getGps() { return gps; } - public void setGps(SiteGPS gps) { this.gps = gps; } @@ -127,7 +127,6 @@ public void setGps(SiteGPS gps) { public Integer getElevationMeters() { return elevationMeters; } - public void setElevationMeters(Integer elevationMeters) { this.elevationMeters = elevationMeters; } @@ -135,7 +134,6 @@ public void setElevationMeters(Integer elevationMeters) { public boolean getUrlDiscuss() { return urlDiscuss; } - public void setUrlDiscuss(boolean urlDiscuss) { this.urlDiscuss = urlDiscuss; } @@ -143,7 +141,6 @@ public void setUrlDiscuss(boolean urlDiscuss) { public int getStallCount() { return stallCount; } - public void setStallCount(int stallCount) { this.stallCount = stallCount; } @@ -151,7 +148,6 @@ public void setStallCount(int stallCount) { public boolean isCounted() { return counted; } - public void setCounted(boolean counted) { this.counted = counted; } @@ -161,7 +157,6 @@ public void setCounted(boolean counted) { public boolean isEnabled() { return enabled; } - public void setEnabled(boolean enabled) { this.enabled = enabled; } @@ -169,7 +164,6 @@ public void setEnabled(boolean enabled) { public String getHours() { return hours; } - public void setHours(String hours) { this.hours = hours; } @@ -177,7 +171,6 @@ public void setHours(String hours) { public String getLocationId() { return locationId; } - public void setLocationId(String locationId) { this.locationId = locationId; } @@ -185,7 +178,6 @@ public void setLocationId(String locationId) { public int getStatusDays() { return statusDays; } - public void setStatusDays(int statusDays) { this.statusDays = statusDays; } @@ -193,7 +185,6 @@ public void setStatusDays(int statusDays) { public int getPowerKilowatt() { return powerKilowatt; } - public void setPowerKilowatt(int powerKilowatt) { this.powerKilowatt = powerKilowatt; } @@ -201,7 +192,6 @@ public void setPowerKilowatt(int powerKilowatt) { public boolean isSolarCanopy() { return solarCanopy; } - public void setSolarCanopy(boolean solarCanopy) { this.solarCanopy = solarCanopy; } @@ -209,7 +199,6 @@ public void setSolarCanopy(boolean solarCanopy) { public boolean isBattery() { return battery; } - public void setBattery(boolean battery) { this.battery = battery; } @@ -217,8 +206,70 @@ public void setBattery(boolean battery) { public boolean isOtherEVs() { return otherEVs; } - public void setOtherEVs(boolean otherEVs) { this.otherEVs = otherEVs; } + + public StallsDTO getStalls() { + return stalls; + } + public void setStalls(StallsDTO stalls) { + this.stalls = stalls; + } + + public PlugsDTO getPlugs() { + return plugs; + } + public void setPlugs(PlugsDTO plugs) { + this.plugs = plugs; + } + + public Integer getParkingId() { + return parkingId; + } + public void setParkingId(Integer parkingId) { + this.parkingId = parkingId; + } + + public String getFacilityName() { + return facilityName; + } + public void setFacilityName(String facilityName) { + this.facilityName = facilityName; + } + + public String getFacilityHours() { + return facilityHours; + } + public void setFacilityHours(String facilityHours) { + this.facilityHours = facilityHours; + } + + public String getAccessNotes() { + return accessNotes; + } + public void setAccessNotes(String accessNotes) { + this.accessNotes = accessNotes; + } + + public String getAddressNotes() { + return addressNotes; + } + public void setAddressNotes(String addressNotes) { + this.addressNotes = addressNotes; + } + + public Long getPlugshareId() { + return plugshareId; + } + public void setPlugshareId(Long plugshareId) { + this.plugshareId = plugshareId; + } + + public Long getOsmId() { + return osmId; + } + public void setOsmId(Long osmId) { + this.osmId = osmId; + } } diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/SiteDTOFunction.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/SiteDTOFunction.java index d803e9a..f2f7eda 100644 --- a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/SiteDTOFunction.java +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/SiteDTOFunction.java @@ -28,6 +28,15 @@ public SiteDTO apply(Site site) { siteDTO.setSolarCanopy(site.isSolarCanopy()); siteDTO.setBattery(site.isBattery()); siteDTO.setOtherEVs(site.isOtherEVs()); + siteDTO.setStalls(StallsDTOFunctions.transform(site.getStalls())); + siteDTO.setPlugs(PlugsDTOFunctions.transform(site.getPlugs())); + siteDTO.setParkingId(site.getParkingId()); + siteDTO.setFacilityName(site.getFacilityName()); + siteDTO.setFacilityHours(site.getFacilityHours()); + siteDTO.setAccessNotes(site.getAccessNotes()); + siteDTO.setAddressNotes(site.getAddressNotes()); + siteDTO.setPlugshareId(site.getPlugshareId()); + siteDTO.setOsmId(site.getOsmId()); return siteDTO; } diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/StallsDTO.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/StallsDTO.java new file mode 100644 index 0000000..1554197 --- /dev/null +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/StallsDTO.java @@ -0,0 +1,82 @@ +package com.redshiftsoft.tesla.web.mvc.site; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.redshiftsoft.tesla.dao.site.Stalls; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class StallsDTO { + + private Integer urban; + private Integer v2; + private Integer v3; + private Integer v4; + private Integer other; + private Integer accessible; + private Integer trailerFriendly; + + public StallsDTO nullIfEmpty() { + return urban == null && v2 == null && v3 == null && v4 == null && other == null && accessible == null && trailerFriendly == null ? null : this; + } + + @JsonIgnore + public int getTotal() { + int total = 0; + if (urban != null) total += urban; + if (v2 != null) total += v2; + if (v3 != null) total += v3; + if (v4 != null) total += v4; + if (other != null) total += other; + return total; + } + + public Integer getUrban() { + return urban; + } + public void setUrban(Integer urban) { + this.urban = urban; + } + + public Integer getV2() { + return v2; + } + public void setV2(Integer v2) { + this.v2 = v2; + } + + public Integer getV3() { + return v3; + } + public void setV3(Integer v3) { + this.v3 = v3; + } + + public Integer getV4() { + return v4; + } + public void setV4(Integer v4) { + this.v4 = v4; + } + + public Integer getOther() { + return other; + } + public void setOther(Integer other) { + this.other = other; + } + + public Integer getAccessible() { + return accessible; + } + public void setAccessible(Integer accessible) { + this.accessible = accessible; + } + + public Integer getTrailerFriendly() { + return trailerFriendly; + } + public void setTrailerFriendly(Integer trailerFriendly) { + this.trailerFriendly = trailerFriendly; + } + +} diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/StallsDTOFunctions.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/StallsDTOFunctions.java new file mode 100644 index 0000000..a95b757 --- /dev/null +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/site/StallsDTOFunctions.java @@ -0,0 +1,60 @@ +package com.redshiftsoft.tesla.web.mvc.site; + +import com.redshiftsoft.tesla.dao.site.Stalls; + +import java.util.function.Function; + +public class StallsDTOFunctions { + + private static final StallsFunction STALLS_FUNCTION = new StallsFunction(); + private static final StallsDTOFunction STALLS_DTO_FUNCTION = new StallsDTOFunction(); + + public static Stalls transform(StallsDTO stallsDTO) { + return STALLS_FUNCTION.apply(stallsDTO); + } + + public static StallsDTO transform(Stalls stalls) { + return STALLS_DTO_FUNCTION.apply(stalls); + } + + private static class StallsDTOFunction implements Function { + + @Override + public StallsDTO apply(Stalls stalls) { + if (stalls == null) return null; + + StallsDTO stallsDTO = new StallsDTO(); + + stallsDTO.setUrban(stalls.getUrban()); + stallsDTO.setV2(stalls.getV2()); + stallsDTO.setV3(stalls.getV3()); + stallsDTO.setV4(stalls.getV4()); + stallsDTO.setOther(stalls.getOther()); + stallsDTO.setAccessible(stalls.getAccessible()); + stallsDTO.setTrailerFriendly(stalls.getTrailerFriendly()); + + return stallsDTO.nullIfEmpty(); + } + } + + private static class StallsFunction implements Function { + + @Override + public Stalls apply(StallsDTO stallsDTO) { + if (stallsDTO == null) return null; + + Stalls stalls = new Stalls(); + + stalls.setUrban(stallsDTO.getUrban()); + stalls.setV2(stallsDTO.getV2()); + stalls.setV3(stallsDTO.getV3()); + stalls.setV4(stallsDTO.getV4()); + stalls.setOther(stallsDTO.getOther()); + stalls.setAccessible(stallsDTO.getAccessible()); + stalls.setTrailerFriendly(stallsDTO.getTrailerFriendly()); + + return stalls.nullIfEmpty(); + } + } + +} \ No newline at end of file diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteDiffLogger.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteDiffLogger.java index 356f166..02d91b7 100644 --- a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteDiffLogger.java +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteDiffLogger.java @@ -1,6 +1,8 @@ package com.redshiftsoft.tesla.web.mvc.siteadmin; +import com.redshiftsoft.tesla.dao.site.Plugs; import com.redshiftsoft.tesla.dao.site.Site; +import com.redshiftsoft.tesla.dao.site.Stalls; import com.redshiftsoft.tesla.dao.sitechanges.SiteChange; import com.redshiftsoft.tesla.dao.sitechanges.SiteChangeBuilder; import com.redshiftsoft.tesla.dao.sitechanges.SiteChangeDAO; @@ -33,6 +35,13 @@ public boolean record(User user, Site oldSite, Site newSite) { int nextVersion = oldSite.getVersion() + 1; SiteChangeBuilder builder = new SiteChangeBuilder(oldSite.getId(), user.getId(), nextVersion, Instant.now()); + Stalls oldStalls = oldSite.getStalls(), newStalls = newSite.getStalls(); + if (oldStalls == null) oldStalls = new Stalls(); + if (newStalls == null) newStalls = new Stalls(); + Plugs oldPlugs = oldSite.getPlugs(), newPlugs = newSite.getPlugs(); + if (oldPlugs == null) oldPlugs = new Plugs(); + if (newPlugs == null) newPlugs = new Plugs(); + diff(builder, "locationId", oldSite.getLocationId(), newSite.getLocationId()); diff(builder, "name", oldSite.getName(), newSite.getName()); diff(builder, "status", oldSite.getStatus(), newSite.getStatus()); @@ -51,6 +60,31 @@ public boolean record(User user, Site oldSite, Site newSite) { diff(builder, "otherEVs", oldSite.isOtherEVs(), newSite.isOtherEVs()); diff(builder, "developerNotes", oldSite.getDeveloperNotes(), newSite.getDeveloperNotes()); + diff(builder, "stallsUrban", oldStalls.getUrban(), newStalls.getUrban()); + diff(builder, "stallsV2", oldStalls.getV2(), newStalls.getV2()); + diff(builder, "stallsV3", oldStalls.getV3(), newStalls.getV3()); + diff(builder, "stallsV4", oldStalls.getV4(), newStalls.getV4()); + diff(builder, "stallsOther", oldStalls.getOther(), newStalls.getOther()); + diff(builder, "stallsAccessible", oldStalls.getAccessible(), newStalls.getAccessible()); + diff(builder, "stallsTrailerFriendly", oldStalls.getTrailerFriendly(), newStalls.getTrailerFriendly()); + + diff(builder, "plugsTPC", oldPlugs.getTPC(), newPlugs.getTPC()); + diff(builder, "plugsNACS", oldPlugs.getNACS(), newPlugs.getNACS()); + diff(builder, "plugsCCS1", oldPlugs.getCCS1(), newPlugs.getCCS1()); + diff(builder, "plugsCCS2", oldPlugs.getCCS2(), newPlugs.getCCS2()); + diff(builder, "plugsType2", oldPlugs.getType2(), newPlugs.getType2()); + diff(builder, "plugsGBT", oldPlugs.getGBT(), newPlugs.getGBT()); + diff(builder, "plugsOther", oldPlugs.getOther(), newPlugs.getOther()); + diff(builder, "plugsMulti", oldPlugs.getMulti(), newPlugs.getMulti()); + + diff(builder, "parkingId", oldSite.getParkingId(), newSite.getParkingId()); + diff(builder, "facilityName", oldSite.getFacilityName(), newSite.getFacilityName()); + diff(builder, "facilityHours", oldSite.getFacilityHours(), newSite.getFacilityHours()); + diff(builder, "accessNotes", oldSite.getAccessNotes(), newSite.getAccessNotes()); + diff(builder, "addressNotes", oldSite.getAddressNotes(), newSite.getAddressNotes()); + diff(builder, "plugshareId", oldSite.getPlugshareId(), newSite.getPlugshareId()); + diff(builder, "osmId", oldSite.getOsmId(), newSite.getOsmId()); + diff(builder, "address.street", oldSite.getAddress().getStreet(), newSite.getAddress().getStreet()); diff(builder, "address.city", oldSite.getAddress().getCity(), newSite.getAddress().getCity()); diff(builder, "address.state", oldSite.getAddress().getState(), newSite.getAddress().getState()); diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditDTO.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditDTO.java index b0ae664..6512280 100644 --- a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditDTO.java +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditDTO.java @@ -10,6 +10,8 @@ import com.redshiftsoft.tesla.web.json.LocalDateSerializer; import com.redshiftsoft.tesla.web.json.LocalDateTimeSerializer; import com.redshiftsoft.tesla.web.mvc.site.AddressDTO; +import com.redshiftsoft.tesla.web.mvc.site.PlugsDTO; +import com.redshiftsoft.tesla.web.mvc.site.StallsDTO; import java.time.LocalDate; import java.time.LocalDateTime; @@ -46,6 +48,13 @@ public class SiteEditDTO { private boolean battery; private boolean otherEVs; + private StallsDTO stalls = new StallsDTO(); + private PlugsDTO plugs = new PlugsDTO(); + + private Integer parkingId; + private String facilityName, facilityHours, accessNotes, addressNotes; + private Long plugshareId, osmId; + // - - - - - - - - - - - - - - - - - - - - - - - // java.lang.Object // - - - - - - - - - - - - - - - - - - - - - - - @@ -96,11 +105,9 @@ public boolean isOpen() { // getters/setters // - - - - - - - - - - - - - - - - - - - - - - - - public int getId() { return id; } - public void setId(int id) { this.id = id; } @@ -108,7 +115,6 @@ public void setId(int id) { public String getName() { return name; } - public void setName(String name) { this.name = name; } @@ -116,7 +122,6 @@ public void setName(String name) { public SiteStatus getStatus() { return status; } - public void setStatus(SiteStatus status) { this.status = status; } @@ -126,7 +131,6 @@ public void setStatus(SiteStatus status) { public LocalDate getDateOpened() { return dateOpened; } - public void setDateOpened(LocalDate dateOpened) { this.dateOpened = dateOpened; } @@ -135,7 +139,6 @@ public void setDateOpened(LocalDate dateOpened) { public LocalDateTime getDateModified() { return dateModified; } - public void setDateModified(LocalDateTime dateModified) { this.dateModified = dateModified; } @@ -143,7 +146,6 @@ public void setDateModified(LocalDateTime dateModified) { public AddressDTO getAddress() { return address; } - public void setAddress(AddressDTO address) { this.address = address; } @@ -151,7 +153,6 @@ public void setAddress(AddressDTO address) { public SiteGPS getGps() { return gps; } - public void setGps(SiteGPS gps) { this.gps = gps; } @@ -159,7 +160,6 @@ public void setGps(SiteGPS gps) { public Integer getElevationMeters() { return elevationMeters; } - public void setElevationMeters(Integer elevationMeters) { this.elevationMeters = elevationMeters; } @@ -167,7 +167,6 @@ public void setElevationMeters(Integer elevationMeters) { public String getUrlDiscuss() { return urlDiscuss; } - public void setUrlDiscuss(String urlDiscuss) { this.urlDiscuss = urlDiscuss; } @@ -175,7 +174,6 @@ public void setUrlDiscuss(String urlDiscuss) { public int getStallCount() { return stallCount; } - public void setStallCount(int stallCount) { this.stallCount = stallCount; } @@ -183,7 +181,6 @@ public void setStallCount(int stallCount) { public boolean isCounted() { return counted; } - public void setCounted(boolean counted) { this.counted = counted; } @@ -193,7 +190,6 @@ public void setCounted(boolean counted) { public boolean isEnabled() { return enabled; } - public void setEnabled(boolean enabled) { this.enabled = enabled; } @@ -201,7 +197,6 @@ public void setEnabled(boolean enabled) { public String getHours() { return hours; } - public void setHours(String hours) { this.hours = hours; } @@ -209,7 +204,6 @@ public void setHours(String hours) { public String getLocationId() { return locationId; } - public void setLocationId(String locationId) { this.locationId = locationId; } @@ -217,7 +211,6 @@ public void setLocationId(String locationId) { public int getPowerKiloWatt() { return powerKiloWatt; } - public void setPowerKiloWatt(int powerKiloWatt) { this.powerKiloWatt = powerKiloWatt; } @@ -225,7 +218,6 @@ public void setPowerKiloWatt(int powerKiloWatt) { public NotifyEnum getNotify() { return notify; } - public void setNotify(NotifyEnum notify) { this.notify = notify; } @@ -233,7 +225,6 @@ public void setNotify(NotifyEnum notify) { public boolean isSolarCanopy() { return solarCanopy; } - public void setSolarCanopy(boolean solarCanopy) { this.solarCanopy = solarCanopy; } @@ -241,7 +232,6 @@ public void setSolarCanopy(boolean solarCanopy) { public boolean isBattery() { return battery; } - public void setBattery(boolean battery) { this.battery = battery; } @@ -249,7 +239,6 @@ public void setBattery(boolean battery) { public String getDeveloperNotes() { return developerNotes; } - public void setDeveloperNotes(String developerNotes) { this.developerNotes = developerNotes; } @@ -257,7 +246,6 @@ public void setDeveloperNotes(String developerNotes) { public int getVersion() { return version; } - public void setVersion(int version) { this.version = version; } @@ -265,11 +253,73 @@ public void setVersion(int version) { public boolean isOtherEVs() { return otherEVs; } - public void setOtherEVs(boolean otherEVs) { this.otherEVs = otherEVs; } + public StallsDTO getStalls() { + return stalls; + } + public void setStalls(StallsDTO stalls) { + this.stalls = stalls; + } + + public PlugsDTO getPlugs() { + return plugs; + } + public void setPlugs(PlugsDTO plugs) { + this.plugs = plugs; + } + + public Integer getParkingId() { + return parkingId; + } + public void setParkingId(Integer parkingId) { + this.parkingId = parkingId; + } + + public String getFacilityName() { + return facilityName; + } + public void setFacilityName(String facilityName) { + this.facilityName = facilityName; + } + + public String getFacilityHours() { + return facilityHours; + } + public void setFacilityHours(String facilityHours) { + this.facilityHours = facilityHours; + } + + public String getAccessNotes() { + return accessNotes; + } + public void setAccessNotes(String accessNotes) { + this.accessNotes = accessNotes; + } + + public String getAddressNotes() { + return addressNotes; + } + public void setAddressNotes(String addressNotes) { + this.addressNotes = addressNotes; + } + + public Long getPlugshareId() { + return plugshareId; + } + public void setPlugshareId(Long plugshareId) { + this.plugshareId = plugshareId; + } + + public Long getOsmId() { + return osmId; + } + public void setOsmId(Long osmId) { + this.osmId = osmId; + } + public enum NotifyEnum { yes, log, no } diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditDTOFunctions.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditDTOFunctions.java index c25e451..a711b5a 100644 --- a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditDTOFunctions.java +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditDTOFunctions.java @@ -2,6 +2,10 @@ import com.redshiftsoft.tesla.dao.site.Site; import com.redshiftsoft.tesla.web.mvc.site.AddressDTOFunctions; +import com.redshiftsoft.tesla.web.mvc.site.PlugsDTO; +import com.redshiftsoft.tesla.web.mvc.site.PlugsDTOFunctions; +import com.redshiftsoft.tesla.web.mvc.site.SiteDTOFunction; +import com.redshiftsoft.tesla.web.mvc.site.StallsDTOFunctions; import java.util.Collection; import java.util.List; @@ -56,6 +60,15 @@ public SiteEditDTO apply(Site site) { siteDTO.setSolarCanopy(site.isSolarCanopy()); siteDTO.setBattery(site.isBattery()); siteDTO.setOtherEVs(site.isOtherEVs()); + siteDTO.setStalls(StallsDTOFunctions.transform(site.getStalls())); + siteDTO.setPlugs(PlugsDTOFunctions.transform(site.getPlugs())); + siteDTO.setParkingId(site.getParkingId()); + siteDTO.setFacilityName(site.getFacilityName()); + siteDTO.setFacilityHours(site.getFacilityHours()); + siteDTO.setAccessNotes(site.getAccessNotes()); + siteDTO.setAddressNotes(site.getAddressNotes()); + siteDTO.setPlugshareId(site.getPlugshareId()); + siteDTO.setOsmId(site.getOsmId()); siteDTO.setDeveloperNotes(site.getDeveloperNotes()); return siteDTO; @@ -89,6 +102,15 @@ public Site apply(SiteEditDTO siteDTO) { site.setSolarCanopy(siteDTO.isSolarCanopy()); site.setBattery(siteDTO.isBattery()); site.setOtherEVs(siteDTO.isOtherEVs()); + site.setStalls(StallsDTOFunctions.transform(siteDTO.getStalls())); + site.setPlugs(PlugsDTOFunctions.transform(siteDTO.getPlugs())); + site.setParkingId(siteDTO.getParkingId()); + site.setFacilityName(siteDTO.getFacilityName()); + site.setFacilityHours(siteDTO.getFacilityHours()); + site.setAccessNotes(siteDTO.getAccessNotes()); + site.setAddressNotes(siteDTO.getAddressNotes()); + site.setPlugshareId(siteDTO.getPlugshareId()); + site.setOsmId(siteDTO.getOsmId()); site.setDeveloperNotes(siteDTO.getDeveloperNotes()); return site; diff --git a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditValidation.java b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditValidation.java index 97c2eda..3fa1686 100644 --- a/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditValidation.java +++ b/service-war/src/main/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditValidation.java @@ -3,6 +3,9 @@ import com.google.common.collect.Lists; import com.redshiftsoft.tesla.dao.site.*; import com.redshiftsoft.tesla.web.mvc.site.AddressDTO; +import com.redshiftsoft.tesla.web.mvc.site.PlugsDTO; +import com.redshiftsoft.tesla.web.mvc.site.StallsDTO; + import org.springframework.stereotype.Component; import javax.annotation.Resource; @@ -67,9 +70,9 @@ private void validateCommon(SiteEditDTO site, List errorMessages) { // // Date Opened // - if (SiteStatus.OPEN.equals(site.getStatus())) { + if (SiteStatus.OPEN.equals(site.getStatus()) || SiteStatus.EXPANDING.equals(site.getStatus())) { if (site.getDateOpened() == null) { - errorMessages.add("missing open date for OPEN site"); + errorMessages.add("missing open date for OPEN or EXPANDING site"); } } else { if (site.getDateOpened() != null) { @@ -111,12 +114,36 @@ private void validateCommon(SiteEditDTO site, List errorMessages) { } // - // stall count + // stall/plug counts // if (site.getStallCount() <= 0) { errorMessages.add("stall count must be at least 1"); } + StallsDTO stalls = site.getStalls(); + if (stalls == null) stalls = new StallsDTO(); + PlugsDTO plugs = site.getPlugs(); + if (plugs == null) plugs = new PlugsDTO(); + + if (site.getStallCount() != stalls.getTotal()) { + errorMessages.add("stall count must equal total of individual stall type counts"); + } + if (stalls.getAccessible() != null && stalls.getAccessible() > site.getStallCount()) { + errorMessages.add("# of accessible stalls cannot be more than total stall count"); + } + if (stalls.getTrailerFriendly() != null && stalls.getTrailerFriendly() > site.getStallCount()) { + errorMessages.add("# of trailer-friendly stalls cannot be more than total stall count"); + } + if (site.getStallCount() != plugs.getTotal() && (plugs.getMulti() == null || plugs.getMulti() == 0)) { + errorMessages.add("stall count must equal total of individual plug type counts (unless any stalls are multi-plug)"); + } + if (plugs.getMulti() != null && plugs.getMulti() > 0 && site.getStallCount() > plugs.getTotal() - plugs.getMulti()) { + errorMessages.add("stall count cannot exceed total of individual plug type counts minus multi-plug count"); + } + + // + // power + // if (site.getPowerKiloWatt() < 0 || site.getPowerKiloWatt() > 500) { errorMessages.add("power must be in range [0,500]"); } @@ -144,6 +171,20 @@ private void validateCommon(SiteEditDTO site, List errorMessages) { } } + // + // China-specific logic: Hong Kong is CCS2 only, Macau is CCS2 or GB/T, the rest of China is GB/T only + // + if (address.getCountry() == "China") { + if (address.getState().toLowerCase() == "hong kong") { + if (plugs.getGBT() > 0) { + errorMessages.add("Hong Kong does not use GB/T plugs"); + } + } else if (address.getState().toLowerCase() != "macau") { + if (plugs.getCCS2() > 0) { + errorMessages.add("China locations (except Hong Kong and Macau) only use GB/T plugs"); + } + } + } } } diff --git a/service-war/src/test/java/com/redshiftsoft/tesla/web/mvc/site/SiteEditValidation_UT.java b/service-war/src/test/java/com/redshiftsoft/tesla/web/mvc/site/SiteEditValidation_UT.java index be99832..cfe00b0 100644 --- a/service-war/src/test/java/com/redshiftsoft/tesla/web/mvc/site/SiteEditValidation_UT.java +++ b/service-war/src/test/java/com/redshiftsoft/tesla/web/mvc/site/SiteEditValidation_UT.java @@ -48,6 +48,10 @@ private SiteEditDTO createTestSite() { site.setDateOpened(LocalDate.now()); site.setGps(new SiteGPS(1, 2)); site.setStallCount(4); + site.setStalls(new StallsDTO()); + site.getStalls().setV3(4); + site.setPlugs(new PlugsDTO()); + site.getPlugs().setNACS(4); site.setElevationMeters(1000); site.setAddress(address); return site; diff --git a/service-war/src/test/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditController_IT.java b/service-war/src/test/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditController_IT.java index 7a40194..5f63761 100644 --- a/service-war/src/test/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditController_IT.java +++ b/service-war/src/test/java/com/redshiftsoft/tesla/web/mvc/siteadmin/SiteEditController_IT.java @@ -111,7 +111,13 @@ public void edit_requires_editor_role() throws Exception { // then - Assertions.assertEquals("{\"result\":\"FAIL\",\"messages\":[\"gps is required\",\"elevation is required\",\"street is required\",\"city is required\",\"country is required\"]}", response); + Assertions.assertEquals("{" + + "\"result\":\"FAIL\",\"messages\":[" + + "\"gps is required\",\"elevation is required\"," + + "\"stall count must equal total of individual stall type counts\"," + + "\"stall count must equal total of individual plug type counts (unless any stalls are multi-plug)\"," + + "\"street is required\",\"city is required\",\"country is required\"" + + "]}", response); } } diff --git a/web-scrape/pom.xml b/web-scrape/pom.xml index 9ea127e..938aaec 100644 --- a/web-scrape/pom.xml +++ b/web-scrape/pom.xml @@ -3,7 +3,7 @@ info.supercharge.api supercharge.info-api - 5.0.3-SNAPSHOT + 5.1.1-SNAPSHOT 4.0.0