mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
bugfix #146
This commit is contained in:
parent
e10ea34dd3
commit
a0419ab3fd
6 changed files with 85 additions and 82 deletions
|
|
@ -30,10 +30,13 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
import jsprit.core.problem.vehicle.Vehicle;
|
import jsprit.core.problem.vehicle.Vehicle;
|
||||||
import jsprit.core.problem.vehicle.VehicleFleetManager;
|
import jsprit.core.problem.vehicle.VehicleFleetManager;
|
||||||
|
import jsprit.core.problem.vehicle.VehicleTypeKey;
|
||||||
import jsprit.core.util.ActivityTimeTracker;
|
import jsprit.core.util.ActivityTimeTracker;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by schroeder on 10.12.14.
|
* Created by schroeder on 10.12.14.
|
||||||
|
|
@ -88,11 +91,20 @@ public class PrettyAlgorithmBuilder {
|
||||||
stateManager.updateTimeWindowStates();
|
stateManager.updateTimeWindowStates();
|
||||||
UpdateVehicleDependentPracticalTimeWindows tw_updater = new UpdateVehicleDependentPracticalTimeWindows(stateManager, vrp.getTransportCosts());
|
UpdateVehicleDependentPracticalTimeWindows tw_updater = new UpdateVehicleDependentPracticalTimeWindows(stateManager, vrp.getTransportCosts());
|
||||||
tw_updater.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
|
tw_updater.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
|
||||||
|
|
||||||
|
Map<VehicleTypeKey,Vehicle> uniqueTypes = new HashMap<VehicleTypeKey,Vehicle>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Vehicle> get(VehicleRoute vehicleRoute) {
|
public Collection<Vehicle> get(VehicleRoute vehicleRoute) {
|
||||||
|
if(uniqueTypes.isEmpty()){
|
||||||
|
for( Vehicle v : vrp.getVehicles()){
|
||||||
|
if(!uniqueTypes.containsKey(v.getVehicleTypeIdentifier())){
|
||||||
|
uniqueTypes.put(v.getVehicleTypeIdentifier(),v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Collection<Vehicle> vehicles = new ArrayList<Vehicle>();
|
Collection<Vehicle> vehicles = new ArrayList<Vehicle>();
|
||||||
vehicles.add(vehicleRoute.getVehicle());
|
vehicles.addAll(uniqueTypes.values());
|
||||||
vehicles.addAll(fleetManager.getAvailableVehicles(vehicleRoute.getVehicle()));
|
|
||||||
return vehicles;
|
return vehicles;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -48,10 +48,7 @@ import jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
import jsprit.core.problem.solution.route.activity.End;
|
import jsprit.core.problem.solution.route.activity.End;
|
||||||
import jsprit.core.problem.solution.route.activity.ReverseActivityVisitor;
|
import jsprit.core.problem.solution.route.activity.ReverseActivityVisitor;
|
||||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||||
import jsprit.core.problem.vehicle.FiniteFleetManagerFactory;
|
import jsprit.core.problem.vehicle.*;
|
||||||
import jsprit.core.problem.vehicle.InfiniteFleetManagerFactory;
|
|
||||||
import jsprit.core.problem.vehicle.Vehicle;
|
|
||||||
import jsprit.core.problem.vehicle.VehicleFleetManager;
|
|
||||||
import jsprit.core.util.ActivityTimeTracker;
|
import jsprit.core.util.ActivityTimeTracker;
|
||||||
import org.apache.commons.configuration.HierarchicalConfiguration;
|
import org.apache.commons.configuration.HierarchicalConfiguration;
|
||||||
import org.apache.commons.configuration.XMLConfiguration;
|
import org.apache.commons.configuration.XMLConfiguration;
|
||||||
|
|
@ -549,17 +546,21 @@ public class VehicleRoutingAlgorithms {
|
||||||
if(stateManager.timeWindowUpdateIsActivated()){
|
if(stateManager.timeWindowUpdateIsActivated()){
|
||||||
UpdateVehicleDependentPracticalTimeWindows timeWindowUpdater = new UpdateVehicleDependentPracticalTimeWindows(stateManager,vrp.getTransportCosts());
|
UpdateVehicleDependentPracticalTimeWindows timeWindowUpdater = new UpdateVehicleDependentPracticalTimeWindows(stateManager,vrp.getTransportCosts());
|
||||||
timeWindowUpdater.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
|
timeWindowUpdater.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
|
||||||
|
Map<VehicleTypeKey,Vehicle> uniqueTypes = new HashMap<VehicleTypeKey,Vehicle>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Vehicle> get(VehicleRoute route) {
|
public Collection<Vehicle> get(VehicleRoute vehicleRoute) {
|
||||||
Collection<Vehicle> vehicles = new ArrayList<Vehicle>();
|
if(uniqueTypes.isEmpty()){
|
||||||
vehicles.add(route.getVehicle());
|
for( Vehicle v : vrp.getVehicles()){
|
||||||
if(switchAllowed) {
|
if(!uniqueTypes.containsKey(v.getVehicleTypeIdentifier())){
|
||||||
vehicles.addAll(vehicleFleetManager.getAvailableVehicles(route.getVehicle()));
|
uniqueTypes.put(v.getVehicleTypeIdentifier(),v);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collection<Vehicle> vehicles = new ArrayList<Vehicle>();
|
||||||
|
vehicles.addAll(uniqueTypes.values());
|
||||||
return vehicles;
|
return vehicles;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
stateManager.addStateUpdater(timeWindowUpdater);
|
stateManager.addStateUpdater(timeWindowUpdater);
|
||||||
activityPolicy = ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_TIME_WINDOW_OPENS;
|
activityPolicy = ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_TIME_WINDOW_OPENS;
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (c) 2014 Stefan Schroeder.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 3.0 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Contributors:
|
|
||||||
* Stefan Schroeder - initial API and implementation
|
|
||||||
******************************************************************************/
|
|
||||||
package jsprit.core.algorithm.recreate;
|
|
||||||
|
|
||||||
import jsprit.core.problem.driver.Driver;
|
|
||||||
import jsprit.core.problem.job.Job;
|
|
||||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
|
||||||
import jsprit.core.problem.vehicle.PenaltyVehicleType;
|
|
||||||
import jsprit.core.problem.vehicle.Vehicle;
|
|
||||||
|
|
||||||
class PenalyzeInsertionCostsWithPenaltyVehicle implements JobInsertionCostsCalculator{
|
|
||||||
|
|
||||||
JobInsertionCostsCalculator base;
|
|
||||||
|
|
||||||
public PenalyzeInsertionCostsWithPenaltyVehicle(JobInsertionCostsCalculator baseInsertionCostsCalculator) {
|
|
||||||
super();
|
|
||||||
this.base = baseInsertionCostsCalculator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InsertionData getInsertionData(VehicleRoute currentRoute,Job newJob, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownCosts) {
|
|
||||||
if(newVehicle.getType() instanceof PenaltyVehicleType){
|
|
||||||
if(currentRoute.getVehicle().getType() instanceof PenaltyVehicleType){
|
|
||||||
InsertionData iData = base.getInsertionData(currentRoute, newJob, newVehicle, newVehicleDepartureTime, newDriver, bestKnownCosts);
|
|
||||||
double penaltyC = iData.getInsertionCost()*((PenaltyVehicleType)newVehicle.getType()).getPenaltyFactor();
|
|
||||||
InsertionData newData = new InsertionData(penaltyC, iData.getPickupInsertionIndex(), iData.getDeliveryInsertionIndex(), iData.getSelectedVehicle(), iData.getSelectedDriver());
|
|
||||||
newData.setAdditionalTime(iData.getAdditionalTime());
|
|
||||||
newData.setVehicleDepartureTime(iData.getVehicleDepartureTime());
|
|
||||||
return newData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return base.getInsertionData(currentRoute, newJob, newVehicle, newVehicleDepartureTime, newDriver, bestKnownCosts);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -137,6 +137,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
|
||||||
}
|
}
|
||||||
double additionalPickupICosts = softActivityConstraint.getCosts(insertionContext, prevAct, pickupShipment, activities.get(i), prevActEndTime);
|
double additionalPickupICosts = softActivityConstraint.getCosts(insertionContext, prevAct, pickupShipment, activities.get(i), prevActEndTime);
|
||||||
double pickupAIC = calculate(insertionContext,prevAct,pickupShipment,activities.get(i),prevActEndTime);
|
double pickupAIC = calculate(insertionContext,prevAct,pickupShipment,activities.get(i),prevActEndTime);
|
||||||
|
|
||||||
TourActivity prevAct_deliveryLoop = pickupShipment;
|
TourActivity prevAct_deliveryLoop = pickupShipment;
|
||||||
double shipmentPickupArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocation(), pickupShipment.getLocation(), prevActEndTime, newDriver, newVehicle);
|
double shipmentPickupArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocation(), pickupShipment.getLocation(), prevActEndTime, newDriver, newVehicle);
|
||||||
double shipmentPickupEndTime = CalculationUtils.getActivityEndTime(shipmentPickupArrTime, pickupShipment);
|
double shipmentPickupEndTime = CalculationUtils.getActivityEndTime(shipmentPickupArrTime, pickupShipment);
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,11 @@ public class VehicleDependentTimeWindowConstraints implements HardActivityConstr
|
||||||
latestArrTimeAtNextAct = states.getActivityState(nextAct, iFacts.getNewVehicle(), InternalStates.LATEST_OPERATION_START_TIME ,Double.class);
|
latestArrTimeAtNextAct = states.getActivityState(nextAct, iFacts.getNewVehicle(), InternalStates.LATEST_OPERATION_START_TIME ,Double.class);
|
||||||
// if(latestArrTimeAtNextAct == null) //try to get latest_operation_start_time of currVehicle
|
// if(latestArrTimeAtNextAct == null) //try to get latest_operation_start_time of currVehicle
|
||||||
// latestArrTimeAtNextAct = states.getActivityState(nextAct, iFacts.getRoute().getVehicle(), StateFactory.LATEST_OPERATION_START_TIME ,Double.class);
|
// latestArrTimeAtNextAct = states.getActivityState(nextAct, iFacts.getRoute().getVehicle(), StateFactory.LATEST_OPERATION_START_TIME ,Double.class);
|
||||||
if(latestArrTimeAtNextAct == null) //otherwise set it to theoretical_latest_operation_startTime
|
if(latestArrTimeAtNextAct == null) {//otherwise set it to theoretical_latest_operation_startTime
|
||||||
latestArrTimeAtNextAct = nextAct.getTheoreticalLatestOperationStartTime();
|
latestArrTimeAtNextAct = nextAct.getTheoreticalLatestOperationStartTime();
|
||||||
|
// throw new IllegalStateException("this is strange and should not be");
|
||||||
|
//ToDo here, there should be another solution
|
||||||
|
}
|
||||||
nextActLocation = nextAct.getLocation();
|
nextActLocation = nextAct.getLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,6 +102,7 @@ public class VehicleDependentTimeWindowConstraints implements HardActivityConstr
|
||||||
if(arrTimeAtNextOnDirectRouteWithNewVehicle > latestArrTimeAtNextAct){
|
if(arrTimeAtNextOnDirectRouteWithNewVehicle > latestArrTimeAtNextAct){
|
||||||
return ConstraintsStatus.NOT_FULFILLED_BREAK;
|
return ConstraintsStatus.NOT_FULFILLED_BREAK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* |--- newAct ---|
|
* |--- newAct ---|
|
||||||
* |--- nextAct ---|
|
* |--- nextAct ---|
|
||||||
|
|
@ -109,9 +113,13 @@ public class VehicleDependentTimeWindowConstraints implements HardActivityConstr
|
||||||
// log.info("check insertion of " + newAct + " between " + prevAct + " and " + nextAct + ". prevActDepTime=" + prevActDepTime);
|
// log.info("check insertion of " + newAct + " between " + prevAct + " and " + nextAct + ". prevActDepTime=" + prevActDepTime);
|
||||||
double arrTimeAtNewAct = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
double arrTimeAtNewAct = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
double endTimeAtNewAct = CalculationUtils.getActivityEndTime(arrTimeAtNewAct, newAct);
|
double endTimeAtNewAct = CalculationUtils.getActivityEndTime(arrTimeAtNewAct, newAct);
|
||||||
double latestArrTimeAtNewAct = Math.min(newAct.getTheoreticalLatestOperationStartTime(),latestArrTimeAtNextAct - routingCosts.getBackwardTransportTime(newAct.getLocation(),nextActLocation,
|
double latestArrTimeAtNewAct =
|
||||||
latestArrTimeAtNextAct,iFacts.getNewDriver(),iFacts.getNewVehicle()));
|
Math.min(newAct.getTheoreticalLatestOperationStartTime(),
|
||||||
|
latestArrTimeAtNextAct -
|
||||||
|
routingCosts.getBackwardTransportTime(newAct.getLocation(),nextActLocation,latestArrTimeAtNextAct,iFacts.getNewDriver(),iFacts.getNewVehicle())
|
||||||
|
- newAct.getOperationTime()
|
||||||
|
);
|
||||||
|
//ToDo: SUSPICIOUS - hier muss noch operation time weg
|
||||||
/*
|
/*
|
||||||
* |--- prevAct ---|
|
* |--- prevAct ---|
|
||||||
* |--- vehicle's arrival @newAct
|
* |--- vehicle's arrival @newAct
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@ package jsprit.core.algorithm;
|
||||||
|
|
||||||
|
|
||||||
import jsprit.core.algorithm.box.SchrimpfFactory;
|
import jsprit.core.algorithm.box.SchrimpfFactory;
|
||||||
|
import jsprit.core.problem.AbstractJob;
|
||||||
import jsprit.core.problem.Location;
|
import jsprit.core.problem.Location;
|
||||||
import jsprit.core.problem.VehicleRoutingProblem;
|
import jsprit.core.problem.VehicleRoutingProblem;
|
||||||
import jsprit.core.problem.VehicleRoutingProblem.FleetSize;
|
import jsprit.core.problem.VehicleRoutingProblem.FleetSize;
|
||||||
|
import jsprit.core.problem.job.Service;
|
||||||
import jsprit.core.problem.job.Shipment;
|
import jsprit.core.problem.job.Shipment;
|
||||||
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
|
|
@ -14,7 +16,6 @@ import jsprit.core.problem.vehicle.VehicleImpl;
|
||||||
import jsprit.core.problem.vehicle.VehicleImpl.Builder;
|
import jsprit.core.problem.vehicle.VehicleImpl.Builder;
|
||||||
import jsprit.core.problem.vehicle.VehicleType;
|
import jsprit.core.problem.vehicle.VehicleType;
|
||||||
import jsprit.core.problem.vehicle.VehicleTypeImpl;
|
import jsprit.core.problem.vehicle.VehicleTypeImpl;
|
||||||
import jsprit.core.reporting.SolutionPrinter;
|
|
||||||
import jsprit.core.util.Coordinate;
|
import jsprit.core.util.Coordinate;
|
||||||
import jsprit.core.util.Solutions;
|
import jsprit.core.util.Solutions;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
@ -27,26 +28,52 @@ import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
public class PDTW_IT {
|
public class PDTW_IT {
|
||||||
|
|
||||||
int nShipments = 200;
|
int nJobs = 200;
|
||||||
int nVehicles = 15;
|
int nVehicles = 40;
|
||||||
Random random = new Random(1623);
|
Random random = new Random(1623);
|
||||||
int nextShipmentId=1;
|
int nextShipmentId=1;
|
||||||
int nextVehicleId=1;
|
int nextVehicleId=1;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void timeWindowsShouldNOTbeBroken() {
|
public void whenDealingWithShipments_timeWindowsShouldNOTbeBroken() {
|
||||||
|
|
||||||
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
|
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
|
||||||
for(int i =0 ; i < nVehicles ; i++){
|
for(int i =0 ; i < nVehicles ; i++){
|
||||||
vrpBuilder.addVehicle(createVehicle());
|
vrpBuilder.addVehicle(createVehicle());
|
||||||
}
|
}
|
||||||
for(int i =0 ; i < nShipments ;i++){
|
for(int i =0 ; i < nJobs;i++){
|
||||||
vrpBuilder.addJob(createShipment());
|
vrpBuilder.addJob(createShipment());
|
||||||
}
|
}
|
||||||
vrpBuilder.setFleetSize(FleetSize.FINITE);
|
vrpBuilder.setFleetSize(FleetSize.FINITE);
|
||||||
VehicleRoutingProblem problem = vrpBuilder.build();
|
VehicleRoutingProblem problem = vrpBuilder.build();
|
||||||
VehicleRoutingAlgorithm algorithm = new SchrimpfFactory().createAlgorithm(problem);
|
VehicleRoutingAlgorithm algorithm = new SchrimpfFactory().createAlgorithm(problem);
|
||||||
algorithm.setMaxIterations(10);
|
algorithm.setMaxIterations(0);
|
||||||
|
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
|
||||||
|
VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions);
|
||||||
|
|
||||||
|
for(VehicleRoute route : bestSolution.getRoutes()){
|
||||||
|
Vehicle v = route.getVehicle();
|
||||||
|
for(TourActivity ta : route.getActivities()){
|
||||||
|
if(ta.getArrTime() > v.getLatestArrival() * 1.00001){
|
||||||
|
assertFalse(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenDealingWithServices_timeWindowsShouldNOTbeBroken() {
|
||||||
|
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
|
||||||
|
for(int i =0 ; i < nVehicles ; i++){
|
||||||
|
vrpBuilder.addVehicle(createVehicle());
|
||||||
|
}
|
||||||
|
for(int i =0 ; i < nJobs;i++){
|
||||||
|
vrpBuilder.addJob(createService());
|
||||||
|
}
|
||||||
|
vrpBuilder.setFleetSize(FleetSize.FINITE);
|
||||||
|
VehicleRoutingProblem problem = vrpBuilder.build();
|
||||||
|
VehicleRoutingAlgorithm algorithm = new SchrimpfFactory().createAlgorithm(problem);
|
||||||
|
algorithm.setMaxIterations(100);
|
||||||
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
|
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
|
||||||
VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions);
|
VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions);
|
||||||
|
|
||||||
|
|
@ -58,13 +85,20 @@ public class PDTW_IT {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SolutionPrinter.print(bestSolution);
|
private AbstractJob createService() {
|
||||||
|
Service.Builder b = Service.Builder.newInstance(Integer.toString(nextShipmentId++));
|
||||||
|
b.addSizeDimension(0, 1);
|
||||||
|
b.setServiceTime(random.nextDouble() * 5);
|
||||||
|
b.setLocation(createLocation());
|
||||||
|
return b.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Location createLocation(){
|
private Location createLocation(){
|
||||||
return loc(new Coordinate(50*random.nextDouble(), 50*random.nextDouble()));
|
return loc(new Coordinate(50*random.nextDouble(), 50*random.nextDouble()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Shipment createShipment(){
|
private Shipment createShipment(){
|
||||||
Shipment.Builder b = Shipment.Builder.newInstance(Integer.toString(nextShipmentId++));
|
Shipment.Builder b = Shipment.Builder.newInstance(Integer.toString(nextShipmentId++));
|
||||||
b.addSizeDimension(0, 1);
|
b.addSizeDimension(0, 1);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue