Skip to content

Commit 18a8e8b

Browse files
dfcoffinclaude
andauthored
feat: ESPI 4.0 Schema Compliance - Phase 17: ProgramDateIdMappings Complete Implementation (#100)
* feat: Phase 17 (Part 1) - ProgramDateIdMapping Core Structure Implements Phases A, B, and G of Issue #28 Phase 17: ProgramDateIdMappings ESPI 4.0 schema compliance. Establishes the foundational enum, embeddable, entity, and database structure per customer.xsd specification. Phase A: Enum and Embeddable Creation - Created ProgramDateKind enum with 4 XSD-defined values (lines 1997-2030) * CUST_DR_PROGRAM_ENROLLMENT_DATE * CUST_DR_PROGRAM_DE_ENROLLMENT_DATE * CUST_DR_PROGRAM_TERM_DATE_REGARDLESS_FINANCIAL * CUST_DR_PROGRAM_TERM_DATE_WITHOUT_FINANCIAL - Created ProgramDateIdMapping @embeddable (customer.xsd lines 1223-1251) * 4 fields: programDateType, code, name, note * Extends Object (not IdentifiedObject) per XSD Phase B: Entity Updates - Updated ProgramDateIdMappingsEntity (customer.xsd lines 269-283) * Added @Embedded programDateIdMapping field * Implemented equals(), hashCode(), toString() methods * Follows Hibernate proxy-safe pattern * relatedLinks infrastructure already present from Issue #97 Phase G: Database Migration - Updated V3 migration: program_date_id_mappings table * Removed non-XSD fields: program_date, program_id * Added XSD-compliant embedded fields: program_date_type, code, name, note * Removed non-ID indexes per CLAUDE.md guidelines * program_date_id_mapping_related_links table already exists from Issue #97 Technical Details: - Follows customer.xsd structure exactly - ProgramDateIdMappingsEntity has ONE field beyond IdentifiedObject - ProgramDateIdMapping is embedded (not separate entity) - Database columns match JPA @column definitions - All 760 existing tests passing - no regressions Remaining Work (Phases C-I): - Phase C: DTO implementation - Phase D: Mapper implementation - Phase E: Repository implementation - Phase F: Service implementation - Phase H: DtoExportService integration - Phase I: Comprehensive testing (48 new tests) Related: Issue #28 (Phase 17: ProgramDateIdMappings) Note: DO NOT close Issue #28 - more phases (18+) remain after Phase 17 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * feat: ESPI 4.0 Schema Compliance - Phase 17: ProgramDateIdMappings C-I Implementation Complete DTO, Mapper, Repository, Service, and Testing implementation for ProgramDateIdMappings customer domain entity per NAESB ESPI 4.0 customer.xsd specification (lines 269-283, 1223-1251, 1997-2030). Phase C: DTO Implementation - Created ProgramDateIdMappingDto for embedded complex type (4 fields) - Updated ProgramDateIdMappingsDto to follow AtomEntryDto pattern - Removed IdentifiedObject fields from resource DTO (handled by wrapper) Phase D: Mapper Implementation - Created ProgramDateIdMappingMapper for embedded object mapping - Created ProgramDateIdMappingsMapper for resource mapping - No explicit ignore mappings (follows DRY principle) Phase E: Repository Implementation - Created ProgramDateIdMappingsRepository extending JpaRepository - ID-based queries only per ESPI standard Phase F: Service Implementation - Created ProgramDateIdMappingsService interface - Created ProgramDateIdMappingsServiceImpl - No UUID generation in service (expects ID set before save) Phase H: DtoExportService Integration - ProgramDateIdMappingsDto already registered in JAXB context - Generic marshalling methods support all customer domain resources Phase I: Comprehensive Testing (787 tests passing, +16 new) - ProgramDateIdMappingsRepositoryTest (11 H2 unit tests) * CRUD operations (5 tests) * Embedded object persistence (4 tests) * IdentifiedObject fields (2 tests) - ProgramDateIdMappingsMySQLIntegrationTest (TestContainers) * CRUD, bulk operations, embedded persistence - ProgramDateIdMappingsPostgreSQLIntegrationTest (TestContainers) * CRUD, bulk operations, embedded persistence All tests verify: - All 4 ProgramDateKind enum values persist correctly - Embedded ProgramDateIdMapping persistence - Null handling for embedded objects and fields - AssertJ chained assertions throughout Related: #28 Phase 17 Builds on: 9639490 (Phases A-G) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent fe77497 commit 18a8e8b

14 files changed

Lines changed: 1544 additions & 91 deletions

File tree

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Green Button Alliance, Inc.
4+
*
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
*/
19+
20+
package org.greenbuttonalliance.espi.common.domain.customer.common;
21+
22+
import jakarta.persistence.*;
23+
import lombok.AllArgsConstructor;
24+
import lombok.Data;
25+
import lombok.NoArgsConstructor;
26+
import org.greenbuttonalliance.espi.common.domain.customer.enums.ProgramDateKind;
27+
28+
import java.io.Serializable;
29+
30+
/**
31+
* Embeddable class for single customer energy efficiency program date mapping.
32+
*
33+
* Per customer.xsd lines 1223-1251, ProgramDateIdMapping extends Object (NOT IdentifiedObject).
34+
* This is an embedded component, not a standalone entity.
35+
*/
36+
@Embeddable
37+
@Data
38+
@NoArgsConstructor
39+
@AllArgsConstructor
40+
public class ProgramDateIdMapping implements Serializable {
41+
42+
/**
43+
* Type of customer energy efficiency program date.
44+
*/
45+
@Enumerated(EnumType.STRING)
46+
@Column(name = "program_date_type", length = 64)
47+
private ProgramDateKind programDateType;
48+
49+
/**
50+
* Code value (may be alphanumeric).
51+
*/
52+
@Column(name = "code", length = 64)
53+
private String code;
54+
55+
/**
56+
* Name associated with code.
57+
*/
58+
@Column(name = "name", length = 256)
59+
private String name;
60+
61+
/**
62+
* Optional description of code.
63+
*/
64+
@Column(name = "note", length = 256)
65+
private String note;
66+
}

openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/customer/entity/ProgramDateIdMappingsEntity.java

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,18 @@
2121

2222
import lombok.*;
2323
import org.greenbuttonalliance.espi.common.domain.common.IdentifiedObject;
24+
import org.greenbuttonalliance.espi.common.domain.customer.common.ProgramDateIdMapping;
2425
import org.hibernate.proxy.HibernateProxy;
2526

2627
import jakarta.persistence.*;
2728
import java.util.Objects;
2829

2930
/**
3031
* Pure JPA/Hibernate entity for ProgramDateIdMappings without JAXB concerns.
31-
*
32-
* [extension] Collection of all customer Energy Efficiency programs
32+
*
33+
* [extension] Collection of all customer Energy Efficiency programs.
34+
* Per customer.xsd lines 269-283, ProgramDateIdMappings extends IdentifiedObject
35+
* and contains a single embedded ProgramDateIdMapping object.
3336
*/
3437
@Entity
3538
@Table(name = "program_date_id_mappings")
@@ -46,10 +49,39 @@
4649
public class ProgramDateIdMappingsEntity extends IdentifiedObject {
4750

4851
/**
49-
* [extension] Program date description
50-
* TODO: Create ProgramDateIdMappingEntity and enable this relationship
52+
* Single customer energy efficiency program date mapping.
53+
* Per customer.xsd, this is the only field in ProgramDateIdMappings beyond IdentifiedObject fields.
5154
*/
52-
// @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
53-
// @JoinColumn(name = "program_date_id_mapping_id")
54-
// private ProgramDateIdMappingEntity programDateIdMapping;
55+
@Embedded
56+
private ProgramDateIdMapping programDateIdMapping;
57+
58+
@Override
59+
public final boolean equals(Object o) {
60+
if (this == o) return true;
61+
if (o == null) return false;
62+
Class<?> oEffectiveClass = o instanceof HibernateProxy hibernateProxy ? hibernateProxy.getHibernateLazyInitializer().getPersistentClass() : o.getClass();
63+
Class<?> thisEffectiveClass = this instanceof HibernateProxy hibernateProxy ? hibernateProxy.getHibernateLazyInitializer().getPersistentClass() : this.getClass();
64+
if (thisEffectiveClass != oEffectiveClass) return false;
65+
ProgramDateIdMappingsEntity that = (ProgramDateIdMappingsEntity) o;
66+
return getId() != null && Objects.equals(getId(), that.getId());
67+
}
68+
69+
@Override
70+
public final int hashCode() {
71+
return this instanceof HibernateProxy hibernateProxy ? hibernateProxy.getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode();
72+
}
73+
74+
@Override
75+
public String toString() {
76+
return getClass().getSimpleName() + "(" +
77+
"id = " + getId() + ", " +
78+
"description = " + getDescription() + ", " +
79+
"created = " + getCreated() + ", " +
80+
"updated = " + getUpdated() + ", " +
81+
"published = " + getPublished() + ", " +
82+
"upLink = " + getUpLink() + ", " +
83+
"selfLink = " + getSelfLink() + ", " +
84+
"programDateIdMapping = " + programDateIdMapping + ", " +
85+
"relatedLinks = " + getRelatedLinks() + ")";
86+
}
5587
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Green Button Alliance, Inc.
4+
*
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
*/
19+
20+
package org.greenbuttonalliance.espi.common.domain.customer.enums;
21+
22+
/**
23+
* Type of Demand Response program date based on ESPI 4.0 customer.xsd specification.
24+
*
25+
* Per customer.xsd lines 1997-2030.
26+
* Note: XSD uses union type, allowing both enumerated values and custom String64 values.
27+
*
28+
* Ordinal mapping:
29+
* 0 = CUST_DR_PROGRAM_ENROLLMENT_DATE
30+
* 1 = CUST_DR_PROGRAM_DE_ENROLLMENT_DATE
31+
* 2 = CUST_DR_PROGRAM_TERM_DATE_REGARDLESS_FINANCIAL
32+
* 3 = CUST_DR_PROGRAM_TERM_DATE_WITHOUT_FINANCIAL
33+
*/
34+
public enum ProgramDateKind {
35+
/**
36+
* Date customer enrolled in Demand Response program.
37+
* Ordinal: 0
38+
*/
39+
CUST_DR_PROGRAM_ENROLLMENT_DATE,
40+
41+
/**
42+
* Date customer terminated enrollment in Demand Response program.
43+
* Ordinal: 1
44+
*/
45+
CUST_DR_PROGRAM_DE_ENROLLMENT_DATE,
46+
47+
/**
48+
* Earliest date customer can terminate Demand Response enrollment, regardless of financial impact.
49+
* Ordinal: 2
50+
*/
51+
CUST_DR_PROGRAM_TERM_DATE_REGARDLESS_FINANCIAL,
52+
53+
/**
54+
* Earliest date customer can terminate Demand Response enrollment, without financial impact.
55+
* Ordinal: 3
56+
*/
57+
CUST_DR_PROGRAM_TERM_DATE_WITHOUT_FINANCIAL
58+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Green Button Alliance, Inc.
4+
*
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
*/
19+
20+
package org.greenbuttonalliance.espi.common.dto.customer;
21+
22+
import jakarta.xml.bind.annotation.XmlAccessType;
23+
import jakarta.xml.bind.annotation.XmlAccessorType;
24+
import jakarta.xml.bind.annotation.XmlElement;
25+
import jakarta.xml.bind.annotation.XmlType;
26+
import lombok.AllArgsConstructor;
27+
import lombok.Getter;
28+
import lombok.NoArgsConstructor;
29+
import lombok.Setter;
30+
import org.greenbuttonalliance.espi.common.domain.customer.enums.ProgramDateKind;
31+
32+
import java.io.Serializable;
33+
34+
/**
35+
* ProgramDateIdMapping DTO for embedded complex type.
36+
* Per ESPI 4.0 customer.xsd lines 1223-1251.
37+
*
38+
* Single customer energy efficiency program date mapping with 4 fields:
39+
* - programDateType: Type of customer energy efficiency program date
40+
* - code: Code value (may be alphanumeric)
41+
* - name: Name associated with code
42+
* - note: Optional description of code
43+
*
44+
* This is an embedded component (extends Object in XSD, not IdentifiedObject).
45+
*/
46+
@XmlAccessorType(XmlAccessType.FIELD)
47+
@XmlType(name = "ProgramDateIdMapping", namespace = "http://naesb.org/espi/customer", propOrder = {
48+
"programDateType", "code", "name", "note"
49+
})
50+
@Getter
51+
@Setter
52+
@NoArgsConstructor
53+
@AllArgsConstructor
54+
public class ProgramDateIdMappingDto implements Serializable {
55+
56+
private static final long serialVersionUID = 1L;
57+
58+
/**
59+
* Type of customer energy efficiency program date.
60+
* Maps to customer.xsd programDateType element (lines 1224-1238).
61+
*/
62+
@XmlElement(name = "programDateType", namespace = "http://naesb.org/espi/customer")
63+
private ProgramDateKind programDateType;
64+
65+
/**
66+
* Code value (may be alphanumeric).
67+
* Maps to customer.xsd code element (lines 1239-1242).
68+
*/
69+
@XmlElement(name = "code", namespace = "http://naesb.org/espi/customer")
70+
private String code;
71+
72+
/**
73+
* Name associated with code.
74+
* Maps to customer.xsd name element (lines 1243-1246).
75+
*/
76+
@XmlElement(name = "name", namespace = "http://naesb.org/espi/customer")
77+
private String name;
78+
79+
/**
80+
* Optional description of code.
81+
* Maps to customer.xsd note element (lines 1247-1250).
82+
*/
83+
@XmlElement(name = "note", namespace = "http://naesb.org/espi/customer")
84+
private String note;
85+
}

0 commit comments

Comments
 (0)