syncing master

This commit is contained in:
Senad Uka
2017-11-21 17:11:29 +01:00
parent 0eee92660a
commit b4e45199b7
47 changed files with 5666 additions and 263 deletions

View File

@@ -5,7 +5,80 @@
- [Production](https://helix-calculator.sunpower.com/)
### Setup
## Local Development and Testing with Docker
##### Dependencies
- Docker: [docs.docker.com/engine/installation](https://docs.docker.com/engine/installation/)
- CircleCi CLI: [Installing and using CircleCi locally](https://circleci.com/docs/2.0/local-jobs/#installing-the-cli-locally)
- Current CircleCi and development image:
[ivannnn/heroku-cedar14-extras:2.0](https://hub.docker.com/r/ivannnn/heroku-cedar14-extras/)
| ivannnn/heroku-cedar14-extras:2.0 |
| ------------- |
| ruby 2.3.5p376 |
| Python 3.5.4 |
| postgresql-9.5 |
| postgresql-client-9.5|
| postgresql-client-9.6 |
| postgresql-client-common |
| postgresql-common |
| postgresql-contrib-9.5 |
| postgresql-server-dev-9.6 |
| redis-server/trusty,now 2:2.8.4-2 amd64 |
| redis-tools/trusty,now 2:2.8.4-2 amd64 |
| google-chrome-stable/stable,now 62.0.3202.94-1 amd64 |
| nodejs/unknown,now 6.12.0-1nodesource1 amd64 |
##### Test locally with CircleCi
- Go to the project dir
- ```circleci build```
##### Develop
- Run the docker container for the 1st time
```docker run -d --name helix -p 5000:5000 --expose 5000 -t ivannnn/heroku-cedar14-extras:2.0```
- Or re start the docker conatiner
```docker container start helix```
- Copy the code to the container
```docker cp . helix:project```
- Log in the docker container
```docker exec -t -i helix /bin/bash```
- Run this commands inside the docker conatiner
```
cd project && \
rm -rf env && \
gem install bundler && \
service postgresql start &&\
service redis-server start &&\
export PGPASSWORD=password &&\
export CIRCLE_TEST_REPORTS=$(pwd) &&\
python3.5 -m venv env &&\
source env/bin/activate &&\
pip install invoke &&\
invoke install &&\
npm install &&\
invoke db_migrate
```
##### Important
- Open another terminal tab, this script watches for changes and pass them
to the docker conatiner, which will restart the web server
```./watch.sh```
## OS steps wihout Docker
#### macOS systems

View File

@@ -1,58 +1,51 @@
machine:
python:
version: 3.5.1
node:
version: 6.1.0
dependencies:
pre:
- pip install invoke
override:
- invoke install
- invoke update_version
database:
override:
- createdb test
- createdb pivotal
- echo "CREATE ROLE pivotal WITH UNENCRYPTED PASSWORD 'password';" | psql -U postgres
- echo "ALTER ROLE pivotal WITH LOGIN;" | psql -U postgres
- echo "GRANT SELECT, UPDATE, INSERT ON ALL TABLES IN SCHEMA test.public TO pivotal;" | psql -U postgres
- echo "GRANT CREATE, CONNECT ON DATABASE test TO pivotal;" | psql -U postgres
- echo "GRANT SELECT, UPDATE, INSERT ON ALL TABLES IN SCHEMA pivotal.public TO pivotal;" | psql -U postgres
- echo "GRANT CREATE, CONNECT ON DATABASE pivotal TO pivotal;" | psql -U postgres
- PYTHONPATH=.:$PYTHONPATH alembic upgrade head
test:
override:
- invoke test_ci
deployment:
staging:
branch: master
commands:
- invoke update_heroku_version staging
- "[[ ! -s \"$(git rev-parse --git-dir)/shallow\" ]] || git fetch --unshallow"
- git push -f git@heroku.com:sp-helix-staging.git $CIRCLE_SHA1:refs/heads/master
- heroku run --app sp-helix-staging invoke db_migrate
- rake ci:deliver
preprod:
branch: preprod
commands:
- invoke update_heroku_version preprod
- "[[ ! -s \"$(git rev-parse --git-dir)/shallow\" ]] || git fetch --unshallow"
- git push -f git@heroku.com:sp-helix-preprod.git $CIRCLE_SHA1:refs/heads/master
- heroku run --app sp-helix-preprod invoke db_migrate
- rake ci:deliver
production:
tag: /release-.*/
commands:
- invoke update_heroku_version production
- "[[ ! -s \"$(git rev-parse --git-dir)/shallow\" ]] || git fetch --unshallow"
- git push -f git@heroku.com:sp-helix-production.git $CIRCLE_SHA1:refs/heads/master
- heroku run --app sp-helix-production invoke db_migrate
- rake ci:deliver
notify:
webhooks:
- url: http://pulse.pivotallabs.com/projects/03ba990f-b8f5-4508-b4c1-19038b2cb791/status
version: 2
jobs:
build:
docker:
- image: ivannnn/heroku_cedar14:2.0
environment:
PGUSER: pivotal
PGPASSWORD: password
PASSWORD: password
environment:
PATH: /usr/local/rvm/gems/ruby-2.3.4/bin:/usr/local/rvm/gems/ruby-2.3.4@global/bin:/usr/local/rvm/rubies/ruby-2.3.4/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/rvm/bin
steps:
- checkout
- run:
name: Set up and Run tests
command: |
source /etc/profile.d/rvm.sh
rvm use 2.3.4
/etc/init.d/postgresql start
python3.4 -m venv env
source env/bin/activate
pip install invoke
invoke install
npm install
invoke db_migrate
invoke test_ci
- deploy:
name: staging
command: |
invoke update_heroku_version staging
"[[ ! -s \"$(git rev-parse --git-dir)/shallow\" ]] || git fetch --unshallow"
git push -f git@heroku.com:sp-helix-staging.git $CIRCLE_SHA1:refs/heads/master
heroku run --app sp-helix-staging invoke db_migrate
rake ci:deliver
name: preprod
command: |
invoke update_heroku_version preprod
"[[ ! -s \"$(git rev-parse --git-dir)/shallow\" ]] || git fetch --unshallow"
git push -f git@heroku.com:sp-helix-preprod.git $CIRCLE_SHA1:refs/heads/master
heroku run --app sp-helix-preprod invoke db_migrate
rake ci:deliver
name: production
commands: |
invoke update_heroku_version production
"[[ ! -s \"$(git rev-parse --git-dir)/shallow\" ]] || git fetch --unshallow"
git push -f git@heroku.com:sp-helix-production.git $CIRCLE_SHA1:refs/heads/master
heroku run --app sp-helix-production invoke db_migrate
rake ci:deliver
notify:
webhooks:
- url: http://pulse.pivotallabs.com/projects/03ba990f-b8f5-4508-b4c1-19038b2cb791/status

View File

@@ -5,6 +5,8 @@ from helix.constants import ebom_parts
from helix.constants.ebom_parts import *
from helix.constants.parts import wire_clip_large, cable_support, cable_support_lid, channel_nut, sunshade
from helix.constants.system_type import SystemType
from helix.constants.inverter_brand import InverterBrand
from helix.forms.ebom_form import InverterBrandForm
class EbomCalculator(object):
@@ -36,11 +38,25 @@ class EbomCalculator(object):
monitors = self.values.power_monitors()
module_type = self.values.module_type()
system_type = self.values.system_type()
is_delta=None
try:
is_delta=(self.values.inverter_brands()[0]['inverter_brand_id']==InverterBrand.DELTA.value)
except IndexError :
#Some tests are calculating bom without providing inverter brand so inverter_brands is empty
#for those tests, inverter brand is irrelevant
is_delta=False
inverter_count = 0
total_ac_run_length = 0
panel_board_counts = [0, 0]
proper_monitor_controller = self.resolve_power_monitor_type()
try:
is_delta = (self.values.inverter_brands()[0]['inverter_brand_id']==InverterBrand.DELTA.value)
except IndexError:
is_delta = False
for power_station in power_stations:
power_station_count = power_station['power_station_quantity']
total_ac_run_length += power_station['ac_run_length']
@@ -75,6 +91,8 @@ class EbomCalculator(object):
for monitor in monitors:
if monitor['power_source'][0] == 'Switch Gear/External':
add_parts_to_list(part_list, {proper_monitor_controller: 1}, 1)
if (is_delta):
add_parts_to_list(part_list, {ethernet_plug: 2},1)
add_parts_to_list(part_list, {wire_clip_large: inverter_count}, self.row_count)
@@ -84,8 +102,9 @@ class EbomCalculator(object):
add_parts_to_list(part_list, {rear_skirt: -1}, ceil(cable_supports*.38))
dependent_part_list = {}
for part, quantity in part_list.items():
dependent_parts = ebom_parts.dependent_parts(module_type, system_type).get(part)
dependent_parts = ebom_parts.dependent_parts(module_type, system_type,is_delta).get(part)
if dependent_parts:
add_parts_to_list(dependent_part_list, dependent_parts, quantity)

View File

@@ -18,32 +18,18 @@ class DualTiltParts(object):
}
def __init__(self, module_type):
if module_type == ModuleType.PSeries:
self.corner_panel_parts = {
left_deflector_1_1: 1,
right_deflector_1_1: 1,
dual_tilt_chassis: 1.5,
module: 2
}
self.north_south_panel_parts = {
left_deflector_1_1: 1,
right_deflector_1_1: 1,
dual_tilt_chassis: 1.5,
module: 2
}
else:
self.corner_panel_parts = {
left_deflector: 1,
right_deflector: 1,
dual_tilt_chassis: 1.5,
module: 2
}
self.north_south_panel_parts = {
left_deflector: 1,
right_deflector: 1,
dual_tilt_chassis: 1.5,
module: 2
}
self.corner_panel_parts = {
left_deflector_1_1: 1,
right_deflector_1_1: 1,
dual_tilt_chassis: 1.5,
module: 2
}
self.north_south_panel_parts = {
left_deflector_1_1: 1,
right_deflector_1_1: 1,
dual_tilt_chassis: 1.5,
module: 2
}
def row_parts(self, module_type):
if module_type == ModuleType.Cell96:

View File

@@ -144,6 +144,7 @@ def standalone_inverter_parts(inverter, system_type, module_type):
phillips_screw: 4 * multiplier,
ac_inverter_bracket: 1 * multiplier,
hex_bolt_1_2: 4,
ethernet_plug: 1.8,
flat_washer_6: 4,
inverter_link_short: v1_1_inverter_links,
inverter_link_long: v1_1_inverter_links,
@@ -195,10 +196,30 @@ def inverter_parts(inverter, module_type):
stump: 6,
}
def dependent_parts(module_type, system_type):
def dependent_parts(module_type, system_type, is_delta):
v1_1_inverter_links = 0
if system_type == SystemType.singleTilt and (module_type == ModuleType.Cell128 or module_type == ModuleType.PSeries):
v1_1_inverter_links = 1
if is_delta:
monitor_controller_480_v_={
monitor_power_plug: 1,
}
else:
monitor_controller_480_v_={
monitor_power_plug: 1,
flat_washer: 4,
channel_nut: 4,
hex_nut_three_eighths_16: 2,
front_legs: 1,
back_legs: 1,
inverter_link: 2,
inverter_rail: 1,
rubber_foot: 3,
hex_bolt_1_2: 9,
mounting_back_plate: 1,
}
return {
panel_board_2: {
harness_ac_inner: 2,
@@ -246,19 +267,7 @@ def dependent_parts(module_type, system_type):
inverter_link_long: v1_1_inverter_links,
inverter_link: -2 * v1_1_inverter_links,
},
monitor_controller_480_v: {
monitor_power_plug: 1,
flat_washer: 4,
channel_nut: 4,
hex_nut_three_eighths_16: 2,
front_legs: 1,
back_legs: 1,
inverter_link: 2,
inverter_rail: 1,
rubber_foot: 3,
hex_bolt_1_2: 9,
mounting_back_plate: 1,
},
monitor_controller_480_v: monitor_controller_480_v_,
monitor_controller_240_v: {},
ac_splice_box: {
hex_bolt_1_2: 4,

View File

@@ -15,6 +15,7 @@ class FileValidationMessage(Enum):
ExpectedTxtFile = 'Invalid file uploaded. Please upload a valid .txt file.'
ExpectedDxfFile = 'Invalid file uploaded. Please upload a valid .dxf file.'
OldDxfFormat = 'Invalid Aurora format uploaded. Please upload a new format.'
PanelsTooClose = 'It appears that the panel coordinates are too close together. Please ensure that panel spacing is correct and that you have selected the correct configuration.'
@classmethod
def invalid_wind_zones(cls, system_type):

View File

@@ -5,6 +5,7 @@ from helix.constants.panel_type import PanelType
class DualTilt128CellConstants(object):
tolerance = 0.1 #require 10% additional space for panel spacing
panel_spacing = (88.24, 82.0) # inches
spacing_size_inches = 5.12 # This is inches
presenter_spacing = (1.5, 1.5)

View File

@@ -5,6 +5,7 @@ from helix.constants.panel_type import PanelType
class DualTilt96CellConstants(object):
tolerance = 0.1 #require 10% additional space for panel spacing
panel_spacing = (88.24, 62.0) # inches
spacing_size_inches = 5.12 # This is inches
presenter_spacing = (1.5, 1)

View File

@@ -5,6 +5,7 @@ from helix.constants.panel_type import PanelType
class DualTiltPSeriesConstants(object):
tolerance = 0.1 #require 10% additional space for panel spacing
panel_spacing = (88.24, 82.0) # inches
spacing_size_inches = 8.8503937 # This is inches
presenter_spacing = (1.5, 1.5)

View File

@@ -8,6 +8,7 @@ from helix.constants.system_type_constants.single_tilt_constants import SingleTi
class SingleTilt128CellConstants(object):
tolerance = 0.1 #require 10% additional space for panel spacing
panel_spacing = (82.0, 60.0) # inches
presenter_spacing = (1.5, 1)
panel_area = 23.29

View File

@@ -7,6 +7,7 @@ from helix.constants.system_type_constants.single_tilt_constants import SingleTi
class SingleTilt96CellConstants(object):
tolerance = 0.1 #require 10% additional space for panel spacing
panel_spacing = (62.0, 60.0) # inches
presenter_spacing = (1, 1)
panel_area = 17.58

View File

@@ -7,6 +7,7 @@ from helix.constants.system_type_constants.single_tilt_constants import SingleTi
class SingleTiltPSeriesConstants(object):
tolerance = 0.1 #require 10% additional space for panel spacing
panel_spacing = (82.0, 61.8755) # inches
presenter_spacing = (1.5, 1)
panel_area = 22.22

View File

@@ -5,8 +5,6 @@ dual_tilt_chassis = ('514056', 'BASE, CHASSIS, DUAL TILT, HELIX ROOF')
dual_tilt_platform = ('514057', 'PLATFORM, CHASSIS, DUAL TILT, HELIX ROOF')
platform_bolt = ('515063', 'SCREW, CAP, SH, M6 X 1 X 12, 18-8 SS (DIN 912)')
left_deflector = ('513841', 'DEFLECTOR, LH, HELIX ROOF')
right_deflector = ('513842', 'DEFLECTOR, RH, HELIX ROOF')
front_skirt = ('515928', 'FRONT SKIRT, HELIX ROOF')
rear_skirt = ('515929', 'REAR SKIRT, HELIX ROOF')
spoiler = ('513836', 'SPOILER, SINGLE TILT, HELIX ROOF')
@@ -59,10 +57,10 @@ inverter_link_long = ('521797', 'LINK TO ARRAY, SHORT, INVERTER RACK, HELIX ROOF
mounting_back_plate = ('518331', 'MOUNTING BACK PLATE, INVERTER/PANEL BOARD, HELIX ROOF/TRACKER')
sma_12kw_inverter = ('514686', 'INVERTER, SMA, STP, 12000TL-US-10 (SPR-12000m-3 XXX), AFCI, CONNECTORIZED')
sma_15kw_inverter = ('514687', 'INVERTER, SMA, STP, 15000TL-US-10 (SPR-15000m-3 XXX), AFCI, CONNECTORIZED')
sma_20kw_inverter = ('512676', 'INVERTER, SMA, STP, 20000TL-US-10 (SPR-20000m-3 XXX), AFCI, CONNECTORIZED')
sma_24kw_inverter = ('514685', 'INVERTER, SMA, STP, 24000TL-US-10 (SPR-24000m-3 XXX), AFCI, CONNECTORIZED')
sma_12kw_inverter = ('523921', 'INVERTER, SMA, STP, 20000TL-US-10 (SPR-20000m-3-H), AFCI, CONNECTORIZED, UTX XL REV D DC CONNECTORS')
sma_15kw_inverter = ('523922', 'INVERTER, SMA, STP, 24000TL-US-10 (SPR-24000m-3-H), AFCI, CONNECTORIZED, UTX XL REV D DC CONNECTORS')
sma_20kw_inverter = ('523923', 'INVERTER, SMA, STP, 12000TL-US-10 (SPR-12000m-3-H), AFCI, CONNECTORIZED, UTX XL REV D DC CONNECTORS')
sma_24kw_inverter = ('523924', 'INVERTER, SMA, STP, 15000TL-US-10 (SPR-15000m-3-H), AFCI, CONNECTORIZED, UTX XL REV D DC CONNECTORS')
delta_36kw_inverter = ('524952', 'INVERTER, DELTA, M36U_122(MC4), 10INPUT, 36KW, 3PH 480V AC,1000V DC')
delta_42kw_inverter = ('524969', 'INVERTER, DELTA, M42U_122(MC4), 12INPUT, 42KW, 3PH 480V AC,1000V DC')
@@ -159,8 +157,6 @@ all_parts = [
dual_tilt_chassis,
dual_tilt_platform,
platform_bolt,
left_deflector,
right_deflector,
front_skirt,
rear_skirt,
spoiler,

View File

@@ -18,32 +18,19 @@ class SingleTiltParts(object):
}
def __init__(self, module_type):
if module_type == ModuleType.PSeries:
self.corner_panel_parts = {
module: 1,
single_tilt_chassis: 1,
left_deflector_1_1: 0.5,
right_deflector_1_1: 0.5,
}
self.east_west_panel_parts = {
module: 1,
single_tilt_chassis: 1.5,
left_deflector_1_1: 0.5,
right_deflector_1_1: 0.5
}
else:
self.corner_panel_parts = {
module: 1,
single_tilt_chassis: 1,
left_deflector: 0.5,
right_deflector: 0.5
}
self.east_west_panel_parts = {
module: 1,
single_tilt_chassis: 1.5,
left_deflector: 0.5,
right_deflector: 0.5
}
self.corner_panel_parts = {
module: 1,
single_tilt_chassis: 1,
left_deflector_1_1: 0.5,
right_deflector_1_1: 0.5,
}
self.east_west_panel_parts = {
module: 1,
single_tilt_chassis: 1.5,
left_deflector_1_1: 0.5,
right_deflector_1_1: 0.5
}
def row_parts(self, _):
return {}

View File

@@ -9,7 +9,10 @@ class ArrayVisualization {
this.isDualTilt = isDualTilt;
this.subarrayDisplay = subarrayDisplay;
this.buildings = buildings;
// Default options
this.scale = 10;
this.panels = [];
}
init() {
@@ -22,12 +25,12 @@ class ArrayVisualization {
this.stage.mouseMoveOutside = true;
this.adjustScale(this.buildings);
this.drawArray(this.container, this.panelData, this.scale);
this.drawArray(this.container, this.panelData);
this.container.x = 0;
this.container.y = 0;
this.stage.addChild(this.container);
this.drawBuildings(this.buildings,this.scale);
this.drawBuildings(this.buildings, this.scale);
this.stage.update();
@@ -76,13 +79,13 @@ class ArrayVisualization {
}
drawBuildings(buildings, scale) {
if (!buildings) {
drawBuildings(buildings) {
if (!buildings || buildings.length === 0) {
console.log("No Buildings!");
return;
}
if (!scale) {
if (!this.scale) {
console.log("No Scale - don't know how big the buildings should be!");
return;
}
@@ -99,14 +102,14 @@ class ArrayVisualization {
line.graphics.beginStroke(color);
line.graphics.moveTo(firstPoint.x * scale, firstPoint.y * scale);
line.graphics.moveTo(firstPoint.x * this.scale, firstPoint.y * this.scale);
for (let j = 1; j < building.length; j++ ) {
nextPoint = building[j];
line.graphics.lineTo(nextPoint.x * scale ,nextPoint.y * scale);
line.graphics.moveTo(nextPoint.x * scale,nextPoint.y * scale);
line.graphics.lineTo(nextPoint.x * this.scale, nextPoint.y * this.scale);
line.graphics.moveTo(nextPoint.x * this.scale, nextPoint.y * this.scale);
}
line.graphics.lineTo(firstPoint.x * scale, firstPoint.y * scale );
line.graphics.lineTo(firstPoint.x * this.scale, firstPoint.y * this.scale );
line.graphics.endStroke();
}
@@ -121,7 +124,7 @@ class ArrayVisualization {
this.container.removeChild(this.panels[i]);
}
this.drawArray(this.container, this.panelData, this.scale);
this.drawArray(this.container, this.panelData);
let selectedPanel = this.selectedPanel;
this.selectedPanel = undefined;
@@ -134,18 +137,14 @@ class ArrayVisualization {
}
drawArray(container, panels) {
this.panels = [];
let treatCoordinatesAsCenterpoints = this.buildings && this.buildings.length > 0;
for (let i = 0; i < panels.length; i++) {
let panel = panels[i];
let box = new Panel(panel, this.isDualTilt, this.scale, treatCoordinatesAsCenterpoints);
let box = new Panel(panels[i], this.isDualTilt, this.scale, treatCoordinatesAsCenterpoints);
container.addChild(box);
this.panels.push(box);
let self = this;
box.on("click", function () {
self.selectPanel(i);
box.on("click", () => {
this.selectPanel(i);
});
}
}

View File

@@ -48,14 +48,11 @@ class ProjectPresenter(object):
# Move coordinates to reflect origin being at top-left
# (as per canvas) instead of bottom-left
# if max_y is not passed - use the panels instead of buildings
if max_y is None:
height = max(map(lambda row: row['y'], table_data))
else:
height = max_y
height = max(map(lambda row: row['y'], table_data))
first_cell = min(map(lambda row: row['y'], table_data))
self.offset = height
for panel in table_data:
panel['y'] = height - panel['y']
panel['y'] = height - panel['y'] + first_cell
return table_data
def get_buildings(self, buildings):
@@ -76,10 +73,6 @@ class ProjectPresenter(object):
point.y = point.y * spacing_y
presentable_building.append(point.__dict__)
for presentable_building in result:
for point in presentable_building:
point['y'] = self.offset - point['y']
return result
def get_max_y(self,buildings, panels):

View File

@@ -122,7 +122,10 @@
this.isDualTilt = isDualTilt;
this.subarrayDisplay = subarrayDisplay;
this.buildings = buildings;
// Default options
this.scale = 10;
this.panels = [];
}
_createClass(ArrayVisualization, [{
@@ -137,7 +140,7 @@
this.stage.mouseMoveOutside = true;
this.adjustScale(this.buildings);
this.drawArray(this.container, this.panelData, this.scale);
this.drawArray(this.container, this.panelData);
this.container.x = 0;
this.container.y = 0;
this.stage.addChild(this.container);
@@ -200,13 +203,13 @@
}
}, {
key: 'drawBuildings',
value: function drawBuildings(buildings, scale) {
if (!buildings) {
value: function drawBuildings(buildings) {
if (!buildings || buildings.length === 0) {
console.log("No Buildings!");
return;
}
if (!scale) {
if (!this.scale) {
console.log("No Scale - don't know how big the buildings should be!");
return;
}
@@ -223,14 +226,14 @@
line.graphics.beginStroke(color);
line.graphics.moveTo(firstPoint.x * scale, firstPoint.y * scale);
line.graphics.moveTo(firstPoint.x * this.scale, firstPoint.y * this.scale);
for (var j = 1; j < building.length; j++) {
nextPoint = building[j];
line.graphics.lineTo(nextPoint.x * scale, nextPoint.y * scale);
line.graphics.moveTo(nextPoint.x * scale, nextPoint.y * scale);
line.graphics.lineTo(nextPoint.x * this.scale, nextPoint.y * this.scale);
line.graphics.moveTo(nextPoint.x * this.scale, nextPoint.y * this.scale);
}
line.graphics.lineTo(firstPoint.x * scale, firstPoint.y * scale);
line.graphics.lineTo(firstPoint.x * this.scale, firstPoint.y * this.scale);
line.graphics.endStroke();
}
@@ -245,7 +248,7 @@
this.container.removeChild(this.panels[i]);
}
this.drawArray(this.container, this.panelData, this.scale);
this.drawArray(this.container, this.panelData);
var selectedPanel = this.selectedPanel;
this.selectedPanel = undefined;
@@ -261,19 +264,15 @@
value: function drawArray(container, panels) {
var _this2 = this;
this.panels = [];
var treatCoordinatesAsCenterpoints = this.buildings && this.buildings.length > 0;
var _loop = function _loop(i) {
var panel = panels[i];
var box = new _panel.Panel(panel, _this2.isDualTilt, _this2.scale, treatCoordinatesAsCenterpoints);
var box = new _panel.Panel(panels[i], _this2.isDualTilt, _this2.scale, treatCoordinatesAsCenterpoints);
container.addChild(box);
_this2.panels.push(box);
var self = _this2;
box.on("click", function () {
self.selectPanel(i);
_this2.selectPanel(i);
});
};

View File

@@ -8,6 +8,9 @@
<link href="//cdn.rawgit.com/noelboss/featherlight/1.7.6/release/featherlight.min.css" type="text/css" rel="stylesheet" />
<link rel="shortcut icon" href="https://us.sunpower.com/sites/sunpower/files/favicon.ico">
<link rel="stylesheet" type="text/css" href={{ url_for('static', filename='css/fontello.css') }}>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
crossorigin="anonymous"></script>
{% if context['google_analytics_token'] %}
<script>
(function (i, s, o, g, r, a, m) {

View File

@@ -8,7 +8,7 @@ from helix.constants.panel_type import PanelType
from helix.constants.system_type import SystemType
from helix.models.coordinate import Coordinate
from helix.models.panel import PanelData, Panel
from helix.models.sql.inverter_brands import InverterBrand
class UserValues(object):
def __init__(self, store, site):
@@ -60,6 +60,9 @@ class UserValues(object):
def power_monitors(self):
return [power_monitor.to_json() for power_monitor in self.site.power_monitors]
def inverter_brands(self):
return [inverter_brands.to_json() for inverter_brands in self.site.inverter_brands]
def csv(self):
csv_data = self.site.cad_file
if not csv_data:
@@ -156,4 +159,3 @@ class UserValues(object):
else:
return False # should not happen, but if it does rather not show the warning

View File

@@ -1,5 +1,7 @@
import csv
from helix.constants.file_validation_error import FileValidationError, FileValidationMessage
from helix.calculators.coordinates_calculator import CoordinatesCalculator
from helix.models.coordinate import Coordinate
class CsvInputValidator(object):
@@ -14,7 +16,7 @@ class CsvInputValidator(object):
if len(headers) < 5:
return FileValidationError(FileValidationMessage.InvalidHeaders, 0)
if len(rows) == 0:
return FileValidationError(FileValidationMessage.InvalidRowCount, 0)
return FileValidationError(FileValidationMessage.InvalidRowCount, 0)
for row_index, row in enumerate(rows):
chain = [
@@ -28,13 +30,14 @@ class CsvInputValidator(object):
file_validation_chain = [
CsvInputValidator.validate_file_for_panel_types,
CsvInputValidator.validate_for_spacing,
]
result = self.run_validation_chain(headers, rows, file_validation_chain)
if result:
return FileValidationError(result, None)
return None
except:
except Exception as inst:
return FileValidationError(FileValidationMessage.Generic, None)
# Row Validators
@@ -75,6 +78,45 @@ class CsvInputValidator(object):
return FileValidationMessage.panel_type_too_few_corners(self.user_values.system_type())
return None
def validate_for_spacing(self, headers, rows):
try:
if len(headers) < 13:
return None
coordinates_calculator = CoordinatesCalculator(self.user_values)
scaling_factor = self.user_values.module_system_constants().tolerance + 1
spacing_x, spacing_y = self.user_values.module_system_constants().panel_spacing
spacing_coordinates = Coordinate(spacing_x*scaling_factor, spacing_y*scaling_factor,0)
spacing_coordinates_scaled = coordinates_calculator.scale(spacing_coordinates)
for row_index, row in enumerate(rows):
first_panel = Coordinate(float(row[11]), float(row[12]), float(row[13]))
first_panel_rotated = coordinates_calculator.rotate(first_panel)
first_panel_scaled = coordinates_calculator.scale(first_panel_rotated)
for row_index2, row2 in enumerate(rows):
if row_index2 <= row_index:
continue
second_panel = Coordinate(float(row2[11]), float(row2[12]), float(row2[13]))
second_panel_rotated = coordinates_calculator.rotate(second_panel)
second_panel_scaled = coordinates_calculator.scale(second_panel_rotated)
x_diff = round(abs(first_panel_scaled.x - second_panel_scaled.x),3)
y_diff = round(abs(first_panel_scaled.y - second_panel_scaled.y),3)
if (x_diff < spacing_coordinates_scaled.x) and (y_diff < spacing_coordinates_scaled.y):
return FileValidationMessage.PanelsTooClose
return None
except Exception as inst:
print("ERROR !!! ")
print(inst)
return FileValidationMessage.Generic
# Helpers
def run_validation_chain(self, headers, data, chain):

4829
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -5,4 +5,5 @@ cssselect==0.9.1
lxml==3.6.0
mockredispy==2.9.0.11
Flask-Testing==0.4.2
splinter[flask]
pillow==3.3.1

View File

@@ -13,7 +13,7 @@ requests==2.11.1
svgwrite==1.1.6
Wand==0.4.3
alembic==0.8.7
psycopg2==2.6.2
psycopg2==2.7.3
invoke==0.13.0
dxfgrabber==0.8.1
rollbar==0.13.11

View File

@@ -1,6 +1,19 @@
module.exports = function (config) {
config.set({
browsers: ['Chrome'],
browsers: [ 'ChromeCI' ],
customLaunchers: {
ChromeCI: {
base: 'Chrome',
flags: [
'--headless',
'--disable-gpu',
'--no-sandbox',
'--remote-debugging-port=9222'
]
}
},
singleRun: true,
// basePath: '',
files: [
{
pattern: 'test_index.js', watched: false

View File

@@ -17,12 +17,12 @@ def test(ctx):
@task
def test_ci(ctx):
run('nosetests --with-xunit --xunit-file $CIRCLE_TEST_REPORTS/nosetests.xml')
test_js_ci(None)
run('nosetests --nologcapture --with-xunit --xunit-file $CIRCLE_TEST_REPORTS/nosetests.xml')
test_js_ci(ctx)
def test_js_ci(ctx):
run('karma start spec/javascripts/karma.config.js --single-run --browsers Chrome')
run('./node_modules/.bin/karma start spec/javascripts/karma.config.js')
@task

View File

@@ -367,7 +367,6 @@ class CalculatorTest(unittest.TestCase):
)
self.site.power_stations = [power_station_1, power_station_2]
assert_array_equal(self.subject.compute_bom(), expected)
def test_documentation_bom(self):
@@ -426,7 +425,7 @@ class CalculatorTest(unittest.TestCase):
('512661', 2),
('512662', 4),
('512663', 2),
('512676', 0),
('523923', 0),
('512910', 1),
('513007', 50),
('513299', 0),
@@ -440,8 +439,6 @@ class CalculatorTest(unittest.TestCase):
('513832', 0),
('513833', 670),
('513836', 0),
('513841', 196),
('513842', 196),
('513843', 262),
('513844', 214),
('514056', 1000),
@@ -455,9 +452,9 @@ class CalculatorTest(unittest.TestCase):
('514440', 0),
('514477', 2),
('514478', 0),
('514685', 0),
('514686', 1),
('514687', 0),
('523924', 0),
('523921', 1),
('523922', 0),
('514697', 1),
('514698', 1),
('514865', 50),
@@ -480,19 +477,19 @@ class CalculatorTest(unittest.TestCase):
('520306', 0),
('521031', 2),
('521363', 0),
('521794', 0),
('521795', 0),
('521797', 0),
('521798', 0),
('522020', 0),
('805615', 2),
('521794', 196),
('521795', 196),
('anchors', 262),
('ballast', 6786),
('modules', 1726)
]
assert_array_equal(sorted(self.subject.documentation_bom()), expected)
assert_array_equal(sorted(self.subject.documentation_bom()), sorted(expected))
# Performance Tests

View File

@@ -147,7 +147,7 @@ class EbomCalculatorTest(unittest.TestCase):
whip_tray: 19,
ac_switch: 3,
ac_splice_box: 2,
ethernet_plug: 7.2,
ethernet_plug: 12.600000000000001,
mounting_back_plate: 23,
sunshade_bolt: 4,
sunshade_washer: 4,
@@ -616,6 +616,56 @@ class EbomCalculatorTest(unittest.TestCase):
assert_dictionary_equal(self.subject.compute_ebom(), expected_output)
def test_computes_ebom_with_power_monitor_DELTA_brand(self):
self.user_values.inverter_brands.return_value = [{'inverter_brand_id':2}]
self.user_values.power_monitors.return_value = [{
'monitor_id': 'foo',
'power_source': ('Switch Gear/External', None)
}]
self.user_values.system_type.return_value = SystemType.singleTilt
self.user_values.module_type.return_value = ModuleType.Cell96
expected_output = {
monitor_power_plug: 1,
stump: 0,
cable_support: 0,
cable_support_lid: 0,
rear_skirt: 0,
monitor_controller_480_v:1,
}
assert_dictionary_equal(self.subject.compute_ebom(), expected_output)
def test_computes_ebom_with_power_monitor_SMA_brand(self):
self.user_values.inverter_brands.return_value = [{'inverter_brand_id':1}]
self.user_values.power_monitors.return_value = [{
'monitor_id': 'foo',
'power_source': ('Switch Gear/External', None)
}]
self.user_values.system_type.return_value = SystemType.singleTilt
self.user_values.module_type.return_value = ModuleType.Cell96
expected_output = {
monitor_power_plug: 1,
stump: 0,
cable_support: 0,
cable_support_lid: 0,
rear_skirt: 0,
monitor_controller_480_v:1,
flat_washer: 4,
channel_nut: 4,
hex_nut_three_eighths_16: 2,
front_legs: 1,
back_legs: 1,
inverter_link: 2,
inverter_rail: 1,
rubber_foot: 3,
hex_bolt_1_2: 9,
mounting_back_plate: 1,
}
assert_dictionary_equal(self.subject.compute_ebom(), expected_output)
def test_computes_ebom_with_aux_plugs_on_switchgear_on_pseries_single_tilt(self):
self.user_values.power_stations.return_value = [
{
@@ -1051,3 +1101,58 @@ class EbomCalculatorTest(unittest.TestCase):
self.subject = EbomCalculator(self.user_values, 171, 98, 104)
assert_dictionary_equal(self.subject.compute_ebom(), expected_output_240_pseries)
def test_computes_ebom_with_power_monitor_DELTA_brand(self):
self.user_values.inverter_brands.return_value = [{'inverter_brand_id':2}]
self.user_values.power_monitors.return_value = [{
'monitor_id': 'foo',
'power_source': ('Switch Gear/External', None)
}]
self.user_values.system_type.return_value = SystemType.singleTilt
self.user_values.module_type.return_value = ModuleType.Cell96
expected_output = {
monitor_power_plug: 1,
stump: 0,
cable_support: 0,
cable_support_lid: 0,
rear_skirt: 0,
monitor_controller_480_v: 1,
ethernet_plug: 2,
}
assert_dictionary_equal(self.subject.compute_ebom(), expected_output)
def test_computes_ebom_with_power_monitor_SMA_brand(self):
self.user_values.inverter_brands.return_value = [{'inverter_brand_id':1}]
self.user_values.power_monitors.return_value = [{
'monitor_id': 'foo',
'power_source': ('Switch Gear/External', None)
}]
self.user_values.system_type.return_value = SystemType.singleTilt
self.user_values.module_type.return_value = ModuleType.Cell96
expected_output = {
monitor_power_plug: 1,
stump: 0,
cable_support: 0,
cable_support_lid: 0,
rear_skirt: 0,
monitor_controller_480_v:1,
flat_washer: 4,
channel_nut: 4,
hex_nut_three_eighths_16: 2,
front_legs: 1,
back_legs: 1,
inverter_link: 2,
inverter_rail: 1,
rubber_foot: 3,
hex_bolt_1_2: 9,
mounting_back_plate: 1,
}
assert_dictionary_equal(self.subject.compute_ebom(), expected_output)

View File

@@ -72,8 +72,8 @@ class MechanicalBomCalculatorWhenDualTilt128CellTest(unittest.TestCase):
expected_output = {
wire_clip: 80,
link_tray: 9,
left_deflector: 10,
right_deflector: 10,
left_deflector_1_1: 10,
right_deflector_1_1: 10,
anchor_plate: 12,
cross_tray_1_1: 3,
dual_tilt_chassis: 26,
@@ -98,8 +98,8 @@ class MechanicalBomCalculatorWhenDualTilt128CellTest(unittest.TestCase):
expected_output = {
wire_clip: 80,
link_tray: 9,
left_deflector: 10,
right_deflector: 10,
left_deflector_1_1: 10,
right_deflector_1_1: 10,
anchor_plate: 12,
cross_tray_1_1: 3,
dual_tilt_chassis: 26,

View File

@@ -73,8 +73,8 @@ class MechanicalBomCalculatorWhenDualTilt96CellTest(unittest.TestCase):
expected_output = {
wire_clip: 80,
link_tray: 9,
left_deflector: 10,
right_deflector: 10,
left_deflector_1_1: 10,
right_deflector_1_1: 10,
anchor_plate: 12,
cross_tray: 3,
dual_tilt_chassis: 26,
@@ -99,8 +99,8 @@ class MechanicalBomCalculatorWhenDualTilt96CellTest(unittest.TestCase):
expected_output = {
wire_clip: 80,
link_tray: 18,
left_deflector: 10,
right_deflector: 10,
left_deflector_1_1: 10,
right_deflector_1_1: 10,
anchor_plate: 12,
cross_tray: 3,
dual_tilt_chassis: 26,

View File

@@ -93,8 +93,8 @@ class MechanicalBomCalculatorWhenSingleTilt128CellTest(unittest.TestCase):
following_tray: 6,
link_tray: 28,
spoiler_1_1: 44,
left_deflector: 11,
right_deflector: 11,
left_deflector_1_1: 11,
right_deflector_1_1: 11,
anchor_plate: 15,
cross_tray_1_1: 5,
rubber_foot: 4.4,

View File

@@ -93,8 +93,8 @@ class MechanicalBomCalculatorWhenSingleTilt96CellTest(unittest.TestCase):
following_tray: 25,
link_tray: 28,
spoiler: 44,
left_deflector: 11,
right_deflector: 11,
left_deflector_1_1: 11,
right_deflector_1_1: 11,
anchor_plate: 15,
cross_tray: 5,
rubber_foot: 4.4,

View File

@@ -574,12 +574,12 @@
},
{
"name" : "total_513841",
"name" : "total_521794",
"value" : "someValue"
},
{
"name" : "total_513842",
"name" : "total_521795",
"value" : "someValue"
},

View File

@@ -0,0 +1,18 @@
HANDLE BLOCKNAME WIND POS SUBARRAY PSF BAL LTRAY XTRAY ANC ID XCOORD YCOORD ANGLE
'B247D *U6006 A 1 1 2.4 0 2 - 1 1 30043.319 -61598.761 2.534306
'B245F *U6006 A 2 1 2.4 0 2 - S 2 29955.165 -61602.663 2.534306
'B2441 *U6006 A 2 1 2.4 0 2 - S 3 29867.012 -61606.565 2.534306
'B2423 *U6006 A 1 1 2.4 0 2 - 1 4 29778.858 -61610.467 2.534306
'B2405 *U6006 A 3 1 2.26 0 1 - S 5 30046.068 -61660.86 2.534306
'B23E7 *U6006 A 4 1 5.94 10 1 - - 6 29957.914 -61664.762 2.534306
'B23C9 *U6006 A 4 1 5.94 10 1 - - 7 29869.76 -61668.664 2.534306
'B23AB *U6006 A 3 1 8.9 18 1 1 - 8 29781.607 -61672.566 2.534306
'B238D *U6007 A 3 1 8.9 18 1 1 - 9 30048.816 -61722.96 2.534306
'B236F *U6007 A 4 1 5.94 10 1 - - 10 29960.663 -61726.861 2.534306
'B2351 *U6007 A 4 1 5.94 10 1 - - 11 29872.509 -61730.763 2.534306
'B2333 *U6007 A 3 1 8.9 18 1 1 - 12 29784.355 -61734.665 2.534306
'B2315 *U6007 A 1 1 2.4 0 2 - 1 13 30051.565 -61785.059 2.534306
'B22F7 *U6007 A 2 1 2.4 0 2 - S 14 29963.411 -61788.961 2.534306
'B22D9 *U6007 A 2 1 2.4 0 2 - S 15 29875.258 -61792.862 2.534306
'B22B6 *U6007 A 1 1 2.4 0 2 - 1 16 29787.104 -61796.764 2.534306

View File

@@ -1,8 +1,6 @@
Part # Description Total
512200 CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 352MM ^ 2 3480
513833 TRAY, LINK, HELIX ROOF 670
513841 DEFLECTOR, LH, HELIX ROOF 196
513842 DEFLECTOR, RH, HELIX ROOF 196
513843 PLATE, ANCHOR, HELIX ROOF 262
513844 TRAY, OPTIONAL BALLAST, HELIX ROOF 214
514056 BASE, CHASSIS, DUAL TILT, HELIX ROOF 1000
@@ -12,6 +10,8 @@ Part # Description Total
515928 FRONT SKIRT, HELIX ROOF 261
517871 TRAY, LEADING, HELIX ROOF, RIVETED VERSION 139
518477 WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS 275
521794 DEFLECTOR, LH, HELIX ROOF V1.1 196
521795 DEFLECTOR, RH, HELIX ROOF V1.1 196
Contractor Supplied Ballast Blocks 6786
TBD Anchors 262
TBD Modules 1726
1 Part # Description Total
2 512200 CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 352MM ^ 2 3480
3 513833 TRAY, LINK, HELIX ROOF 670
513841 DEFLECTOR, LH, HELIX ROOF 196
513842 DEFLECTOR, RH, HELIX ROOF 196
4 513843 PLATE, ANCHOR, HELIX ROOF 262
5 513844 TRAY, OPTIONAL BALLAST, HELIX ROOF 214
6 514056 BASE, CHASSIS, DUAL TILT, HELIX ROOF 1000
10 515928 FRONT SKIRT, HELIX ROOF 261
11 517871 TRAY, LEADING, HELIX ROOF, RIVETED VERSION 139
12 518477 WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS 275
13 521794 DEFLECTOR, LH, HELIX ROOF V1.1 196
14 521795 DEFLECTOR, RH, HELIX ROOF V1.1 196
15 Contractor Supplied Ballast Blocks 6786
16 TBD Anchors 262
17 TBD Modules 1726

View File

@@ -10,13 +10,10 @@
512661 BACK LEGS, INVERTER RACK, HELIX ROOF 18
512662 LINK TO ARRAY, INVERTER RACK, HELIX ROOF 36
512663 RAIL, INVERTER RACK, HELIX ROOF 18
512676 INVERTER, SMA, STP, 20000TL-US-10 (SPR-20000m-3 XXX), AFCI, CONNECTORIZED 3
513007 BOLT, HH, 3/8-16 X 3/4, 316 SS 50
513299 COMBINER BOX, AC, 4 INPUT, NO AUX, W/ CONNECTOR 3
513303 COMBINER BOX, AC, 2 INPUT, NO AUX, W/ CONNECTOR 1
513833 TRAY, LINK, HELIX ROOF 670
513841 DEFLECTOR, LH, HELIX ROOF 196
513842 DEFLECTOR, RH, HELIX ROOF 196
513843 PLATE, ANCHOR, HELIX ROOF 262
513844 TRAY, OPTIONAL BALLAST, HELIX ROOF 214
514056 BASE, CHASSIS, DUAL TILT, HELIX ROOF 1000
@@ -30,9 +27,6 @@
514440 HARNESS, DC COMBINATION, W/ FUSE, 4 STRING, MALES TO FEMALE, HELIX 15
514477 HARNESS, AC, INNER, 72", HELIX ROOFTOP 8
514478 HARNESS, AC, OUTER, 108", HELIX ROOFTOP 6
514685 INVERTER, SMA, STP, 24000TL-US-10 (SPR-24000m-3 XXX), AFCI, CONNECTORIZED 9
514686 INVERTER, SMA, STP, 12000TL-US-10 (SPR-12000m-3 XXX), AFCI, CONNECTORIZED 1
514687 INVERTER, SMA, STP, 15000TL-US-10 (SPR-15000m-3 XXX), AFCI, CONNECTORIZED 1
514697 COMM CABLE, INVERTER DAISY CHAIN, 118", HELIX ROOF 10
514865 BOLT, HH, 3/8-16 X 1/2, 18-8 SS 300
515059 ASSY, WHIP TRAY W/FUSE CLIPS, INVERTER, HELIX 14
@@ -42,6 +36,12 @@
518058 CONNECTOR, ETHERNET, PLUG, RJ-45, WEATHERPROOF, SHIELDED 8
518331 MOUNTING BACK PLATE, INVERTER/PANEL BOARD, HELIX ROOF/TRACKER 18
518477 WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS 275
521794 DEFLECTOR, LH, HELIX ROOF V1.1 196
521795 DEFLECTOR, RH, HELIX ROOF V1.1 196
523921 INVERTER, SMA, STP, 20000TL-US-10 (SPR-20000m-3-H), AFCI, CONNECTORIZED, UTX XL REV D DC CONNECTORS 1
523922 INVERTER, SMA, STP, 24000TL-US-10 (SPR-24000m-3-H), AFCI, CONNECTORIZED, UTX XL REV D DC CONNECTORS 1
523923 INVERTER, SMA, STP, 12000TL-US-10 (SPR-12000m-3-H), AFCI, CONNECTORIZED, UTX XL REV D DC CONNECTORS 3
523924 INVERTER, SMA, STP, 15000TL-US-10 (SPR-15000m-3-H), AFCI, CONNECTORIZED, UTX XL REV D DC CONNECTORS 9
Contractor Supplied Ballast Blocks 6786
TBD Anchors 262
TBD Modules 1726
Can't render this file because it contains an unexpected character in line 28 and column 30.

View File

@@ -27,8 +27,6 @@ Part # Description Total
513832 TRAY, FOLLOWING, HELIX ROOF 210
513833 TRAY, LINK, HELIX ROOF 1271
513836 SPOILER, SINGLE TILT, HELIX ROOF 1632
513841 DEFLECTOR, LH, HELIX ROOF 171
513842 DEFLECTOR, RH, HELIX ROOF 171
513843 PLATE, ANCHOR, HELIX ROOF 414
513844 TRAY, OPTIONAL BALLAST, HELIX ROOF 274
514265 FOOT, RECYCLED RUBBER, HELIX ROOF 230
@@ -40,9 +38,6 @@ Part # Description Total
514440 HARNESS, DC COMBINATION, W/ FUSE, 4 STRING, MALES TO FEMALE, HELIX 11
514477 HARNESS, AC, INNER, 72", HELIX ROOFTOP 12
514478 HARNESS, AC, OUTER, 108", HELIX ROOFTOP 2
514685 INVERTER, SMA, STP, 24000TL-US-10 (SPR-24000m-3 XXX), AFCI, CONNECTORIZED 6
514686 INVERTER, SMA, STP, 12000TL-US-10 (SPR-12000m-3 XXX), AFCI, CONNECTORIZED 6
514687 INVERTER, SMA, STP, 15000TL-US-10 (SPR-15000m-3 XXX), AFCI, CONNECTORIZED 3
514697 COMM CABLE, INVERTER DAISY CHAIN, 118", HELIX ROOF 8
514698 DC SWITCH BOX, HELIX 5
514865 BOLT, HH, 3/8-16 X 1/2, 18-8 SS 350
@@ -52,10 +47,15 @@ Part # Description Total
516043 AC SWITCH, CONNECTORIZED, HELIX ROOF 2
516045 AC SPLICE BOX, CONNECTORIZED, HELIX ROOF 1
517871 TRAY, LEADING, HELIX ROOF, RIVETED VERSION 210
518058 CONNECTOR, ETHERNET, PLUG, RJ-45, WEATHERPROOF, SHIELDED 11
518058 CONNECTOR, ETHERNET, PLUG, RJ-45, WEATHERPROOF, SHIELDED 15
518331 MOUNTING BACK PLATE, INVERTER/PANEL BOARD, HELIX ROOF/TRACKER 22
518477 WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS 425
521031 WASHER, FLAT, M10 X 20MM OD, SS 10
521794 DEFLECTOR, LH, HELIX ROOF V1.1 171
521795 DEFLECTOR, RH, HELIX ROOF V1.1 171
523921 INVERTER, SMA, STP, 20000TL-US-10 (SPR-20000m-3-H), AFCI, CONNECTORIZED, UTX XL REV D DC CONNECTORS 6
523922 INVERTER, SMA, STP, 24000TL-US-10 (SPR-24000m-3-H), AFCI, CONNECTORIZED, UTX XL REV D DC CONNECTORS 3
523924 INVERTER, SMA, STP, 15000TL-US-10 (SPR-15000m-3-H), AFCI, CONNECTORIZED, UTX XL REV D DC CONNECTORS 6
805615 SCREW, HEXAGONAL HEAD, M10X20, SS A2 10
Contractor Supplied Ballast Blocks 10150
TBD Anchors 414
Can't render this file because it contains an unexpected character in line 10 and column 30.

View File

@@ -0,0 +1,3 @@
HANDLE BLOCKNAME WIND POS SUBARRAY PSF BAL LTRAY XTRAY ANC ID XCOORD YCOORD ANGLE
'40EC39 *U5399 A 1 1 2.4 0 2 - 1 1 0 0 0
'40EC22 *U5402 A 1 1 2.4 0 2 - 1 2 0 0 0

View File

@@ -0,0 +1,4 @@
HANDLE BLOCKNAME WIND POS SUBARRAY PSF BAL LTRAY XTRAY ANC ID XCOORD YCOORD ANGLE
'40EC39 *U5399 A 1 1 2.4 0 2 - 1 1 0 0 0
'40EC22 *U5402 A 1 1 2.4 0 2 - 1 2 0 0 0
1 HANDLE BLOCKNAME WIND POS SUBARRAY PSF BAL LTRAY XTRAY ANC ID XCOORD YCOORD ANGLE
2 '40EC39 *U5399 A 1 1 2.4 0 2 - 1 1 0 0 0
3 '40EC22 *U5402 A 1 1 2.4 0 2 - 1 2 0 0 0

289
test/fixtures/invalid_too_close.txt vendored Normal file
View File

@@ -0,0 +1,289 @@
HANDLE BLOCKNAME WIND POS SUBARRAY PSF BAL LTRAY XTRAY ANC ID XCOORD YCOORD ANGLE
'1A9103 *U5693 A 1 15 2.4 0 2 - 1 1 128094.142 122996.9 0.0
'1A90DD *U5695 A 3 15 10.77 23 1 2 - 2 128094.142 123059.06 0.0
'1A90B7 *U5695 A 3 15 2.26 0 1 - S 3 128094.142 123121.22 0.0
'1A9091 *U5695 A 3 15 2.26 0 1 - S 4 128094.142 123183.38 0.0
'1A906B *U5695 A 3 15 10.77 23 1 2 - 5 128094.142 123245.54 0.0
'1A9045 *U5693 A 1 15 2.4 0 2 - 1 6 128094.142 123307.7 0.0
'1A900B *U5693 A 1 17 2.4 0 2 - 1 7 125981.9 123804.98 0.0
'1A8FE2 *U5695 B 3 12 2.26 0 1 - S 8 126246.62 123804.98 0.0
'1A8FBC *U5693 B 1 12 9.43 19 2 1 - 9 126158.38 123556.34 0.0
'1A8F96 *U5693 B 1 12 2.4 0 2 - S 10 126158.38 123494.18 0.0
'1A8F70 *U5693 A 1 13 2.4 0 2 - 1 11 126438.62 124426.58 0.0
'1A8F4A *U5693 B 1 13 2.4 0 2 - S 12 126791.58 124177.94 0.0
'1A8ECF *U5693 B 1 14 9.43 19 2 1 - 13 127232.78 123059.06 0.0
'1A8EA9 *U5695 B 3 14 7.81 15 1 1 - 14 127232.78 123121.22 0.0
'1A8E83 *U5694 A 2 15 2.4 0 2 - S 15 128005.902 122996.9 0.0
'1A8E37 *U5682 A 4 15 7.81 15 2 1 - 16 128005.902 123059.06 0.0
'1A8E11 *U5693 B 1 14 9.43 19 2 1 - 17 127585.74 123680.66 0.0
'1A8DEB *U5694 B 2 14 7.93 15 2 - - 18 127497.5 123307.7 0.0
'1A8DC5 *U5693 B 1 13 9.43 19 2 1 - 19 126615.1 124240.1 0.0
'1A8D9F *U5693 B 1 13 2.4 0 2 - S 20 126615.1 124302.26 0.0
'1A8D79 *U5693 B 1 13 2.4 0 2 - S 21 126879.82 124115.78 0.0
'1A8D53 *U5695 A 3 12 2.26 0 1 - S 22 125981.9 124115.78 0.0
'1A8D2D *U5695 A 3 13 10.77 23 1 2 - 23 126438.62 124115.78 0.0
'1A8D07 *U5695 A 3 13 2.26 0 1 - S 24 126438.62 124364.42 0.0
'1A8CE1 *U5682 B 4 12 2.26 0 - - S 25 126246.62 123494.18 0.0
'1A8CBB *U5695 B 3 13 7.81 15 1 1 - 26 126438.62 123742.82 0.0
'1A8C95 *U5695 A 3 13 10.77 23 1 2 - 27 126438.62 123369.86 0.0
'1A8C6F *U5693 A 1 12 2.4 0 2 - 1 28 126246.62 122996.9 0.0
'1A8C49 *U5693 A 1 12 2.4 0 2 - 1 29 126334.86 122996.9 0.0
'1A8C23 *U5693 A 1 13 2.4 0 2 - 1 30 126438.62 122996.9 0.0
'1A8BFD *U5693 B 1 13 2.4 0 2 - S 31 126526.86 122996.9 0.0
'1A8BD7 *U5695 A 3 13 2.26 0 1 - S 32 126438.62 123059.06 0.0
'1A8BB1 *U5695 B 3 13 2.26 0 1 - S 33 126526.86 123059.06 0.0
'1A8B8B *U5695 B 3 13 7.81 15 1 1 - 34 126526.86 123121.22 0.0
'1A8B65 *U5695 A 3 13 10.77 23 1 2 - 35 126438.62 123121.22 0.0
'1A8B3F *U5682 B 4 13 5.58 9 2 - - 36 126879.82 123121.22 0.0
'1A8B19 *U5682 B 4 13 5.58 9 2 - - 37 126879.82 123369.86 0.0
'1A7874 *U5693 A 1 11 2.4 0 2 - 1 38 125962.34 122948.6 0.0
'1A784E *U5695 A 3 11 10.77 23 1 2 - 39 125962.34 123010.76 0.0
'1A7828 *U5695 A 3 11 2.26 0 1 - S 40 125962.34 123072.92 0.0
'1A7802 *U5694 A 2 11 2.4 0 2 - S 41 125874.1 122948.6 0.0
'1A77DC *U5695 A 3 11 10.77 23 1 2 - 42 125785.86 123010.76 0.0
'1A77B6 *U5695 A 3 11 10.77 23 1 2 - 43 125785.86 123072.92 0.0
'1A7790 *U5694 A 2 11 2.4 0 2 - S 44 125785.86 122948.6 0.0
'1A776A *U5693 A 1 11 2.4 0 2 - 1 45 125697.62 123321.56 0.0
'1A7744 *U5693 A 1 11 2.4 0 2 - 1 46 125962.34 123321.56 0.0
'1A771E *U5693 A 1 11 2.4 0 2 - 1 47 125697.62 122948.6 0.0
'1A76F8 *U5695 A 3 11 10.77 23 1 2 - 48 125697.62 123010.76 0.0
'1A76D2 *U5695 A 3 11 10.77 23 1 2 - 49 125697.62 123072.92 0.0
'1A7094 *U5682 B 4 13 5.58 9 2 - - 50 126879.82 123059.06 0.0
'1A706E *U5695 B 3 13 7.81 15 1 1 - 51 126791.58 123059.06 0.0
'1A7048 *U5695 B 3 13 7.81 15 1 1 - 52 126791.58 123121.22 0.0
'1A6FFC *U5695 B 3 13 7.81 15 1 1 - 53 126968.06 123059.06 0.0
'1A6FD6 *U5695 B 3 13 2.26 0 1 - S 54 126968.06 123121.22 0.0
'1A6F64 *U5693 B 1 13 2.4 0 2 - S 55 126791.58 122996.9 0.0
'1A6F3B *U5693 B 1 13 2.4 0 2 - S 56 126968.06 122996.9 0.0
'1A6F15 *U5695 A 3 12 10.77 23 1 2 - 57 126334.86 123059.06 0.0
'1A6EEF *U5695 A 3 12 10.77 23 1 2 - 58 126334.86 123121.22 0.0
'1A6EC9 *U5694 B 2 13 7.93 15 2 - - 59 126879.82 122996.9 0.0
'1A6EA3 *U5695 A 3 12 2.26 0 1 - S 60 126246.62 123059.06 0.0
'1A6E7D *U5695 A 3 12 10.77 23 1 2 - 61 126246.62 123121.22 0.0
'1A6D0B *U5695 A 3 17 10.77 23 1 2 - 62 127829.422 123494.18 0.0
'1A6CE5 *U5695 A 3 17 10.77 23 1 2 - 63 127409.26 123742.82 0.0
'1A6CBF *U5695 A 3 18 10.77 23 1 2 - 64 126158.38 123991.46 0.0
'1A6C99 *U5693 A 1 18 2.4 0 2 - 1 65 126070.14 123991.46 0.0
'1A6C73 *U5695 B 3 13 7.81 15 1 1 - 66 126791.58 124115.78 0.0
'1A6C27 *U5693 B 1 13 2.4 0 2 - S 67 126526.86 124364.42 0.0
'1A6BB5 *U5695 B 3 13 7.81 15 1 1 - 68 126968.06 123369.86 0.0
'1A6B8F *U5695 B 3 12 7.81 15 1 1 - 69 126334.86 123494.18 0.0
'1A696E *U5695 B 3 12 7.81 15 1 1 - 70 126334.86 123804.98 0.0
'1A67DF *U5693 A 1 17 2.4 0 2 - 1 71 128182.382 123307.7 0.0
'1A67B9 *U5693 A 1 18 2.4 0 2 - 1 72 126158.38 123432.02 0.0
'197EB9 *U5693 B 1 14 9.43 19 2 1 - 73 127585.74 123307.7 0.0
'194556 *U5682 A 4 15 7.81 15 2 1 - 74 128005.902 123121.22 0.0
'194530 *U5682 A 4 15 7.81 15 2 1 - 75 128005.902 123183.38 0.0
'19450A *U5682 A 4 15 7.81 15 2 1 - 76 128005.902 123245.54 0.0
'1944E4 *U5694 A 2 15 2.4 0 2 - S 77 128005.902 123307.7 0.0
'1947B6 *U5694 A 2 15 2.4 0 2 - S 78 127917.662 122996.9 0.0
'194790 *U5682 A 4 15 7.81 15 2 1 - 79 127917.662 123059.06 0.0
'19476A *U5682 A 4 15 7.81 15 2 1 - 80 127917.662 123121.22 0.0
'194744 *U5682 A 4 15 7.81 15 2 1 - 81 127917.662 123183.38 0.0
'19471E *U5682 A 4 15 7.81 15 2 1 - 82 127917.662 123245.54 0.0
'1946F8 *U5682 A 4 15 2.26 0 - - S 83 127917.662 123307.7 0.0
'1946D2 *U5695 B 3 15 7.81 15 1 1 - 84 127917.662 123369.86 0.0
'1946AC *U5693 B 1 15 2.4 0 2 - S 85 127917.662 123432.02 0.0
'194686 *U5693 A 1 15 2.4 0 2 - 1 86 127829.422 122996.9 0.0
'194660 *U5695 A 3 15 2.26 0 1 - S 87 127829.422 123059.06 0.0
'19463A *U5695 A 3 15 10.77 23 1 2 - 88 127829.422 123121.22 0.0
'194614 *U5695 A 3 15 10.77 23 1 2 - 89 127829.422 123183.38 0.0
'1945EE *U5695 A 3 15 2.26 0 1 - S 90 127829.422 123245.54 0.0
'1945C8 *U5695 A 3 15 10.77 23 1 2 - 91 127829.422 123307.7 0.0
'1945A2 *U5695 B 3 15 2.26 0 1 - S 92 127829.422 123369.86 0.0
'19457C *U5693 B 1 15 2.4 0 2 - S 93 127829.422 123432.02 0.0
'194828 *U5694 A 2 18 10.89 23 2 1 - 94 127144.54 123618.5 0.0
'194802 *U5693 B 1 14 9.43 19 2 1 - 95 127321.02 123742.82 0.0
'1947DC *U5693 B 1 14 9.43 19 2 1 - 96 127232.78 123742.82 0.0
'194874 *U5695 B 3 14 7.81 15 1 1 - 97 127232.78 123183.38 0.0
'19484E *U5695 B 3 14 7.81 15 1 1 - 98 127232.78 123245.54 0.0
'1948C0 *U5695 A 3 18 10.77 23 1 2 - 99 127144.54 123494.18 0.0
'19489A *U5693 A 1 17 2.4 0 2 - 1 100 127144.54 123556.34 0.0
'194932 *U5694 B 2 14 7.93 15 2 - - 101 127409.26 123307.7 0.0
'19490C *U5694 B 2 14 7.93 15 2 - - 102 127321.02 123307.7 0.0
'1948E6 *U5695 B 3 14 7.81 15 1 1 - 103 127232.78 123307.7 0.0
'194CE8 *U5695 B 3 14 7.81 15 1 1 - 104 127585.74 123369.86 0.0
'194CC2 *U5695 B 3 14 7.81 15 1 1 - 105 127585.74 123432.02 0.0
'194C9C *U5695 B 3 14 7.81 15 1 1 - 106 127585.74 123494.18 0.0
'194C76 *U5695 B 3 14 7.81 15 1 1 - 107 127585.74 123556.34 0.0
'194C50 *U5695 B 3 14 7.81 15 1 1 - 108 127585.74 123618.5 0.0
'194C2A *U5682 B 4 14 5.58 9 2 - - 109 127497.5 123369.86 0.0
'194C04 *U5682 B 4 14 5.58 9 2 - - 110 127497.5 123432.02 0.0
'194BDE *U5682 B 4 14 5.58 9 2 - - 111 127497.5 123494.18 0.0
'194BB8 *U5682 B 4 14 5.58 9 2 - - 112 127497.5 123556.34 0.0
'194B92 *U5682 B 4 14 5.58 9 2 - - 113 127497.5 123618.5 0.0
'194B6C *U5682 B 4 14 5.58 9 2 - - 114 127409.26 123369.86 0.0
'194B46 *U5682 B 4 14 5.58 9 2 - - 115 127409.26 123432.02 0.0
'194B20 *U5682 B 4 14 5.58 9 2 - - 116 127409.26 123494.18 0.0
'194AFA *U5682 B 4 14 5.58 9 2 - - 117 127409.26 123556.34 0.0
'194AD4 *U5682 B 4 14 5.58 9 2 - - 118 127409.26 123618.5 0.0
'194AAE *U5682 B 4 14 5.58 9 2 - - 119 127321.02 123369.86 0.0
'194A88 *U5682 B 4 14 5.58 9 2 - - 120 127321.02 123432.02 0.0
'194A62 *U5682 B 4 14 5.58 9 2 - - 121 127321.02 123494.18 0.0
'194A3C *U5682 B 4 14 5.58 9 2 - - 122 127321.02 123556.34 0.0
'194A16 *U5682 B 4 14 5.58 9 2 - - 123 127321.02 123618.5 0.0
'1949F0 *U5695 B 3 14 7.81 15 1 1 - 124 127232.78 123369.86 0.0
'1949CA *U5695 B 3 14 7.81 15 1 1 - 125 127232.78 123432.02 0.0
'1949A4 *U5695 B 3 14 7.81 15 1 1 - 126 127232.78 123494.18 0.0
'19497E *U5695 B 3 14 7.81 15 1 1 - 127 127232.78 123556.34 0.0
'194958 *U5695 B 3 14 7.81 15 1 1 - 128 127232.78 123618.5 0.0
'194D80 *U5694 B 2 14 7.93 15 2 - - 129 127497.5 123680.66 0.0
'194D5A *U5694 B 2 14 7.93 15 2 - - 130 127409.26 123680.66 0.0
'194D34 *U5682 B 4 14 5.58 9 2 - - 131 127321.02 123680.66 0.0
'194D0E *U5695 B 3 14 7.81 15 1 1 - 132 127232.78 123680.66 0.0
'194E8A *U5695 B 3 13 2.26 0 1 - S 133 126526.86 124115.78 0.0
'194F6E *U5695 B 3 13 7.81 15 1 1 - 134 126526.86 124177.94 0.0
'194F48 *U5682 B 4 13 2.26 0 - - S 135 126526.86 124240.1 0.0
'194F22 *U5682 B 4 13 5.58 9 2 - - 136 126526.86 124302.26 0.0
'194EFC *U5695 A 3 13 2.26 0 1 - S 137 126438.62 124177.94 0.0
'194ED6 *U5695 A 3 13 10.77 23 1 2 - 138 126438.62 124240.1 0.0
'194EB0 *U5695 A 3 13 10.77 23 1 2 - 139 126438.62 124302.26 0.0
'194FBA *U5695 A 3 12 10.77 23 1 2 - 140 125981.9 124053.62 0.0
'194F94 *U5695 B 3 13 2.26 0 1 - S 141 126526.86 123369.86 0.0
'195052 *U5695 B 3 13 2.26 0 1 - S 142 126526.86 123991.46 0.0
'19502C *U5695 B 3 13 7.81 15 1 1 - 143 126526.86 124053.62 0.0
'195006 *U5695 B 3 13 2.26 0 1 - S 144 126438.62 123991.46 0.0
'194FE0 *U5695 A 3 13 10.77 23 1 2 - 145 126438.62 124053.62 0.0
'195136 *U5695 B 3 13 2.26 0 1 - S 146 126526.86 123183.38 0.0
'195110 *U5695 B 3 13 2.26 0 1 - S 147 126526.86 123245.54 0.0
'1950EA *U5695 B 3 13 7.81 15 1 1 - 148 126526.86 123307.7 0.0
'1950C4 *U5695 A 3 13 10.77 23 1 2 - 149 126438.62 123183.38 0.0
'19509E *U5695 A 3 13 2.26 0 1 - S 150 126438.62 123245.54 0.0
'195078 *U5695 A 3 13 10.77 23 1 2 - 151 126438.62 123307.7 0.0
'19515C *U5695 B 3 13 2.26 0 1 - S 152 126438.62 123804.98 0.0
'1951A8 *U5695 B 3 13 2.26 0 1 - S 153 126526.86 123432.02 0.0
'195182 *U5695 A 3 13 2.26 0 1 - S 154 126438.62 123432.02 0.0
'195240 *U5695 B 3 13 7.81 15 1 1 - 155 126526.86 123618.5 0.0
'19521A *U5695 B 3 13 2.26 0 1 - S 156 126526.86 123680.66 0.0
'1951F4 *U5695 B 3 13 2.26 0 1 - S 157 126438.62 123618.5 0.0
'1951CE *U5695 B 3 13 7.81 15 1 1 - 158 126438.62 123680.66 0.0
'195266 *U5695 B 3 13 7.81 15 1 1 - 159 126526.86 123742.82 0.0
'1954A0 *U5695 B 3 13 7.81 15 1 1 - 160 126968.06 123183.38 0.0
'19547A *U5695 B 3 13 7.81 15 1 1 - 161 126968.06 123245.54 0.0
'195454 *U5695 B 3 13 2.26 0 1 - S 162 126968.06 123307.7 0.0
'19542E *U5682 B 4 13 5.58 9 2 - - 163 126879.82 123183.38 0.0
'195408 *U5682 B 4 13 5.58 9 2 - - 164 126879.82 123245.54 0.0
'1953E2 *U5682 B 4 13 5.58 9 2 - - 165 126879.82 123307.7 0.0
'1953BC *U5695 B 3 13 2.26 0 1 - S 166 126791.58 123183.38 0.0
'195396 *U5695 B 3 13 7.81 15 1 1 - 167 126791.58 123245.54 0.0
'195370 *U5695 B 3 13 7.81 15 1 1 - 168 126791.58 123307.7 0.0
'1954C6 *U5695 B 3 13 2.26 0 1 - S 169 126791.58 123369.86 0.0
'1955F6 *U5694 B 2 13 7.93 15 2 - - 170 126703.34 123494.18 0.0
'1955D0 *U5694 B 2 13 2.4 0 2 - S 171 126703.34 123556.34 0.0
'1955AA *U5694 B 2 13 2.4 0 2 - S 172 126615.1 123494.18 0.0
'195584 *U5694 B 2 13 7.93 15 2 - - 173 126615.1 123556.34 0.0
'19555E *U5682 B 4 13 2.26 0 - - S 174 126526.86 123494.18 0.0
'195538 *U5682 B 4 13 2.26 0 - - S 175 126526.86 123556.34 0.0
'195512 *U5695 B 3 13 7.81 15 1 1 - 176 126438.62 123494.18 0.0
'1954EC *U5695 B 3 13 7.81 15 1 1 - 177 126438.62 123556.34 0.0
'195830 *U5695 B 3 13 7.81 15 1 1 - 178 126968.06 123432.02 0.0
'19580A *U5695 B 3 13 2.26 0 1 - S 179 126968.06 123494.18 0.0
'1957E4 *U5695 B 3 13 7.81 15 1 1 - 180 126968.06 123556.34 0.0
'1957BE *U5695 B 3 13 7.81 15 1 1 - 181 126968.06 123618.5 0.0
'195798 *U5693 B 1 13 2.4 0 2 - S 182 126968.06 123680.66 0.0
'195772 *U5682 B 4 13 5.58 9 2 - - 183 126879.82 123432.02 0.0
'19574C *U5682 B 4 13 5.58 9 2 - - 184 126879.82 123494.18 0.0
'195726 *U5682 B 4 13 5.58 9 2 - - 185 126879.82 123556.34 0.0
'195700 *U5682 B 4 13 5.58 9 2 - - 186 126879.82 123618.5 0.0
'1956DA *U5694 B 2 13 2.4 0 2 - S 187 126879.82 123680.66 0.0
'1956B4 *U5695 B 3 13 7.81 15 1 1 - 188 126791.58 123432.02 0.0
'19568E *U5682 B 4 13 2.26 0 - - S 189 126791.58 123494.18 0.0
'195668 *U5682 B 4 13 5.58 9 2 - - 190 126791.58 123556.34 0.0
'195642 *U5695 B 3 13 2.26 0 1 - S 191 126791.58 123618.5 0.0
'19561C *U5693 B 1 13 9.43 19 2 1 - 192 126791.58 123680.66 0.0
'195856 *U5695 B 3 13 7.81 15 1 1 - 193 126526.86 123804.98 0.0
'195986 *U5694 B 2 13 7.93 15 2 - - 194 126703.34 123867.14 0.0
'195960 *U5694 B 2 13 7.93 15 2 - - 195 126703.34 123929.3 0.0
'19593A *U5694 B 2 13 2.4 0 2 - S 196 126615.1 123867.14 0.0
'195914 *U5694 B 2 13 2.4 0 2 - S 197 126615.1 123929.3 0.0
'1958EE *U5682 B 4 13 2.26 0 - - S 198 126526.86 123867.14 0.0
'1958C8 *U5682 B 4 13 5.58 9 2 - - 199 126526.86 123929.3 0.0
'1958A2 *U5695 B 3 13 7.81 15 1 1 - 200 126438.62 123867.14 0.0
'19587C *U5695 B 3 13 7.81 15 1 1 - 201 126438.62 123929.3 0.0
'195BC0 *U5693 B 1 13 2.4 0 2 - S 202 126968.06 123804.98 0.0
'195B9A *U5695 B 3 13 7.81 15 1 1 - 203 126968.06 123867.14 0.0
'195B74 *U5695 B 3 13 2.26 0 1 - S 204 126968.06 123929.3 0.0
'195B4E *U5695 B 3 13 7.81 15 1 1 - 205 126968.06 123991.46 0.0
'195B28 *U5693 B 1 13 2.4 0 2 - S 206 126968.06 124053.62 0.0
'195B02 *U5694 B 2 13 7.93 15 2 - - 207 126879.82 123804.98 0.0
'195ADC *U5682 B 4 13 5.58 9 2 - - 208 126879.82 123867.14 0.0
'195AB6 *U5682 B 4 13 5.58 9 2 - - 209 126879.82 123929.3 0.0
'195A90 *U5682 B 4 13 5.58 9 2 - - 210 126879.82 123991.46 0.0
'195A6A *U5682 B 4 13 5.58 9 2 - - 211 126879.82 124053.62 0.0
'195A44 *U5693 B 1 13 2.4 0 2 - S 212 126791.58 123804.98 0.0
'195A1E *U5682 B 4 13 2.26 0 - - S 213 126791.58 123867.14 0.0
'1959F8 *U5682 B 4 13 2.26 0 - - S 214 126791.58 123929.3 0.0
'1959D2 *U5695 B 3 13 7.81 15 1 1 - 215 126791.58 123991.46 0.0
'1959AC *U5695 B 3 13 2.26 0 1 - S 216 126791.58 124053.62 0.0
'195D88 *U5695 A 3 11 2.26 0 1 - S 217 125962.34 123135.08 0.0
'195D62 *U5695 A 3 11 10.77 23 1 2 - 218 125962.34 123197.24 0.0
'195D3C *U5695 A 3 11 2.26 0 1 - S 219 125962.34 123259.4 0.0
'195D16 *U5694 A 2 11 10.89 23 2 1 - 220 125874.1 123135.08 0.0
'195CF0 *U5682 A 4 11 7.81 15 2 1 - 221 125874.1 123197.24 0.0
'195CCA *U5694 A 2 11 2.4 0 2 - S 222 125874.1 123259.4 0.0
'195CA4 *U5682 A 4 11 7.81 15 2 1 - 223 125785.86 123135.08 0.0
'195C7E *U5682 A 4 11 7.81 15 2 1 - 224 125785.86 123197.24 0.0
'195C58 *U5694 A 2 11 2.4 0 2 - S 225 125785.86 123259.4 0.0
'195C32 *U5695 A 3 11 2.26 0 1 - S 226 125697.62 123135.08 0.0
'195C0C *U5695 A 3 11 10.77 23 1 2 - 227 125697.62 123197.24 0.0
'195BE6 *U5695 A 3 11 2.26 0 1 - S 228 125697.62 123259.4 0.0
'195F04 *U5695 A 3 12 2.26 0 1 - S 229 126334.86 123183.38 0.0
'195EDE *U5695 A 3 12 10.77 23 1 2 - 230 126334.86 123245.54 0.0
'195EB8 *U5695 A 3 12 10.77 23 1 2 - 231 126334.86 123307.7 0.0
'195E92 *U5695 A 3 12 2.26 0 1 - S 232 126334.86 123369.86 0.0
'195E6C *U5695 A 3 12 10.77 23 1 2 - 233 126334.86 123432.02 0.0
'195E46 *U5695 A 3 12 10.77 23 1 2 - 234 126246.62 123183.38 0.0
'195E20 *U5695 A 3 12 2.26 0 1 - S 235 126246.62 123245.54 0.0
'195DFA *U5695 A 3 12 2.26 0 1 - S 236 126246.62 123307.7 0.0
'195DD4 *U5695 A 3 12 10.77 23 1 2 - 237 126246.62 123369.86 0.0
'195DAE *U5695 A 3 12 2.26 0 1 - S 238 126246.62 123432.02 0.0
'19605A *U5695 B 3 12 2.26 0 1 - S 239 126334.86 123556.34 0.0
'196034 *U5695 B 3 12 7.81 15 1 1 - 240 126334.86 123618.5 0.0
'19600E *U5695 B 3 12 7.81 15 1 1 - 241 126334.86 123680.66 0.0
'195FE8 *U5695 B 3 12 2.26 0 1 - S 242 126334.86 123742.82 0.0
'195FC2 *U5682 B 4 12 5.58 9 2 - - 243 126246.62 123556.34 0.0
'195F9C *U5695 B 3 12 7.81 15 1 1 - 244 126246.62 123618.5 0.0
'195F76 *U5695 B 3 12 7.81 15 1 1 - 245 126246.62 123680.66 0.0
'195F50 *U5695 B 3 12 7.81 15 1 1 - 246 126246.62 123742.82 0.0
'196294 *U5695 A 3 12 10.77 23 1 2 - 247 125981.9 124177.94 0.0
'19626E *U5693 A 1 12 2.4 0 2 - 1 248 125981.9 124240.1 0.0
'196248 *U5682 A 4 18 7.81 15 2 1 - 249 126703.34 123804.98 0.0
'196222 *U5694 A 2 12 2.4 0 2 - S 250 125893.66 124177.94 0.0
'1961FC *U5694 A 2 12 10.89 23 2 1 - 251 125893.66 124240.1 0.0
'1961D6 *U5695 A 3 18 10.77 23 1 2 - 252 126615.1 123804.98 0.0
'1961B0 *U5694 A 2 12 2.4 0 2 - S 253 125805.42 124177.94 0.0
'19618A *U5694 A 2 12 2.4 0 2 - S 254 125805.42 124240.1 0.0
'196164 *U5694 A 2 18 10.89 23 2 1 - 255 126158.38 123804.98 0.0
'19613E *U5694 A 2 12 10.89 23 2 1 - 256 125717.18 124177.94 0.0
'196118 *U5694 A 2 12 2.4 0 2 - S 257 125717.18 124240.1 0.0
'1960F2 *U5693 A 1 18 2.4 0 2 - 1 258 126070.14 123804.98 0.0
'1960CC *U5693 A 1 12 2.4 0 2 - 1 259 125628.94 124177.94 0.0
'1960A6 *U5693 A 1 12 2.4 0 2 - 1 260 125628.94 124240.1 0.0
'196080 *U5693 A 1 16 2.4 0 2 - 1 261 126615.1 123432.02 0.0
'196306 *U5695 B 3 12 7.81 15 1 1 - 262 125981.9 123991.46 0.0
'1963EA *U5694 B 2 12 2.4 0 2 - S 263 126158.38 123867.14 0.0
'1963C4 *U5694 B 2 12 7.93 15 2 - - 264 126158.38 123929.3 0.0
'19639E *U5694 B 2 12 2.4 0 2 - S 265 126070.14 123867.14 0.0
'196378 *U5694 B 2 12 2.4 0 2 - S 266 126070.14 123929.3 0.0
'196352 *U5695 B 3 12 7.81 15 1 1 - 267 125981.9 123867.14 0.0
'19632C *U5695 B 3 12 2.26 0 1 - S 268 125981.9 123929.3 0.0
'1966E2 *U5695 B 3 12 7.81 15 1 1 - 269 126334.86 123867.14 0.0
'1966BC *U5695 B 3 12 2.26 0 1 - S 270 126334.86 123929.3 0.0
'196696 *U5695 B 3 12 7.81 15 1 1 - 271 126334.86 123991.46 0.0
'196670 *U5695 A 3 12 10.77 23 1 2 - 272 126334.86 124053.62 0.0
'19664A *U5695 A 3 12 2.26 0 1 - S 273 126334.86 124115.78 0.0
'196624 *U5695 A 3 12 10.77 23 1 2 - 274 126334.86 124177.94 0.0
'1965FE *U5693 A 1 12 2.4 0 2 - 1 275 126334.86 124240.1 0.0
'1965D8 *U5695 A 3 18 10.77 23 1 2 - 276 127144.54 123432.02 0.0
'1965B2 *U5682 A 4 18 7.81 15 2 1 - 277 126703.34 123991.46 0.0
'19658C *U5693 A 1 16 2.4 0 2 - 1 278 128182.382 123245.54 0.0
'196566 *U5682 B 4 12 5.58 9 2 - - 279 126246.62 123867.14 0.0
'196540 *U5682 B 4 12 2.26 0 - - S 280 126246.62 123929.3 0.0
'19651A *U5695 B 3 12 7.81 15 1 1 - 281 126246.62 123991.46 0.0
'1964F4 *U5695 A 3 12 2.26 0 1 - S 282 126246.62 124053.62 0.0
'1964CE *U5695 A 3 12 10.77 23 1 2 - 283 126246.62 124115.78 0.0
'1964A8 *U5695 A 3 12 10.77 23 1 2 - 284 126246.62 124177.94 0.0
'196482 *U5693 A 1 12 2.4 0 2 - 1 285 126246.62 124240.1 0.0
'19645C *U5693 A 1 18 2.4 0 2 - 1 286 126703.34 123432.02 0.0
'196436 *U5693 B 1 12 9.43 19 2 1 - 287 126615.1 123991.46 0.0
'196410 *U5693 A 1 17 2.4 0 2 - 1 288 127232.78 122996.9 0.0

View File

@@ -290,7 +290,7 @@ class DocGenParamsBuilderTest(unittest.TestCase):
('513832', 0),
('513833', 790),
('513836', 0),
('513841', 196),
('521794', 196),
('anchors', 262),
('ballast', 6786),
@@ -304,7 +304,7 @@ class DocGenParamsBuilderTest(unittest.TestCase):
'total_513832': 0,
'total_513833': 790,
'total_513836': 0,
'total_513841': 196,
'total_521794': 196,
'total_anchors': 262,
'total_ballast': 6786,
'total_modules': 1726

View File

@@ -67,10 +67,12 @@ class PanelPresenterTest(unittest.TestCase):
def test_get_buildings_data(self):
self.subject = ProjectPresenter(SystemType.singleTilt, ModuleType.Cell96)
buildings = [ [ Coordinate(-60,-60), Coordinate(60,-60), Coordinate(60,60), Coordinate(-60,60) ] ] # big square
expected_buildings = [[ {'x': -60, '_Coordinate__rounded_x': -60, 'y': 60, '_Coordinate__rounded_y': -60, 'rotation': 0.0},
{'x': 60, '_Coordinate__rounded_x': 60, 'y': 60, '_Coordinate__rounded_y': -60, 'rotation': 0.0},
{'x': 60, '_Coordinate__rounded_x': 60, 'y': -60, '_Coordinate__rounded_y': 60, 'rotation': 0.0},
{'x': -60, '_Coordinate__rounded_x': -60, 'y': -60, '_Coordinate__rounded_y': 60, 'rotation': 0.0}]]
expected_buildings = [[
{'x': -60, '_Coordinate__rounded_x': -60, 'y': -60, '_Coordinate__rounded_y': -60, 'rotation': 0.0},
{'x': 60, '_Coordinate__rounded_x': 60, 'y': -60, '_Coordinate__rounded_y': -60, 'rotation': 0.0},
{'x': 60, '_Coordinate__rounded_x': 60, 'y': 60, '_Coordinate__rounded_y': 60, 'rotation': 0.0},
{'x': -60, '_Coordinate__rounded_x': -60, 'y': 60, '_Coordinate__rounded_y': 60, 'rotation': 0.0}
]]
actual_buildings = self.subject.get_buildings(buildings)
assert_array_equal(actual_buildings,expected_buildings)

View File

@@ -1,3 +1,4 @@
import time
from flask.ext.testing import LiveServerTestCase
import mockredis
from splinter import Browser
@@ -65,6 +66,7 @@ class ArraySummaryDynamicTest(LiveServerTestCase):
def test_shows_subarray_summary_table_if_user_has_uploaded_data(self):
self.fill_in_site_characterization_data()
self.upload_cad_block_file('test/fixtures/input_single_tilt_csv_for_bom.csv')
time.sleep(3)
assert len(self.browser.find_by_css('.upload_field .error_message')) == 0
assert len(self.browser.find_by_css("#seismic_anchor_table")) > 0
eq_(len(self.browser.find_by_css("#seismic_anchor_table tr")), 4)
@@ -73,6 +75,7 @@ class ArraySummaryDynamicTest(LiveServerTestCase):
def test_shows_errors_if_user_tries_to_upload_select_invalid_data(self):
self.fill_in_site_characterization_data()
self.upload_cad_block_file('test/fixtures/invalid_wind_zone.csv')
time.sleep(3)
assert len(self.browser.find_by_id('error_message_txt')) > 0
assert len(self.browser.find_by_css("#seismic_anchor_table")) == 0
@@ -87,30 +90,29 @@ class ArraySummaryDynamicTest(LiveServerTestCase):
def test_indicates_that_user_has_already_uploaded_a_csv_file_after_uploading(self):
self.fill_in_site_characterization_data()
self.upload_cad_block_file('test/fixtures/input_single_tilt_csv_for_bom.csv')
time.sleep(3)
assert len(self.browser.find_by_css('.upload_field .error_message')) == 0
assert 'input_single_tilt_csv_for_bom.csv' in self.browser.html
def test_adding_seismic_anchor_updates_subarray_summary(self):
self.fill_in_site_characterization_data()
self.upload_cad_block_file('test/fixtures/input_single_tilt_csv_for_bom.csv')
time.sleep(3)
assert self.browser.is_element_visible_by_css('#arrayCanvas')
self.browser.execute_script('arrayVisualization.selectPanel(1631);')
self.browser.find_by_css('#add_seismic').click()
assert self.browser.find_by_css('#current_anchors td:nth-child(14)').text == '1'
self.browser.find_by_css('#add_seismic').click()
assert self.browser.find_by_css('#current_anchors td:nth-child(14)').text == '2'
def test_removig_seismic_anchor_updates_subarray_summary(self):
self.fill_in_site_characterization_data()
self.upload_cad_block_file('test/fixtures/input_single_tilt_csv_for_bom.csv')
time.sleep(3)
assert self.browser.is_element_visible_by_css('#arrayCanvas')
self.browser.execute_script('arrayVisualization.selectPanel(1631);')
self.browser.find_by_css('#add_seismic').click()
assert self.browser.find_by_css('#current_anchors td:nth-child(14)').text == '1'
self.browser.find_by_css('#remove_seismic').click()
assert self.browser.find_by_css('#current_anchors td:nth-child(14)').text == '0'

View File

@@ -37,8 +37,6 @@ class BomIntegrationTest(unittest.TestCase):
expected = [
["512200", "CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 352MM ^ 2", "510"],
["513833", "TRAY, LINK, HELIX ROOF", "78"], # TODO: should be 74 for part perfect bom
["513841", "DEFLECTOR, LH, HELIX ROOF", "30"],
["513842", "DEFLECTOR, RH, HELIX ROOF", "30"],
["513843", "PLATE, ANCHOR, HELIX ROOF", "86"],
["513844", "TRAY, OPTIONAL BALLAST, HELIX ROOF", "35"],
["514056", "BASE, CHASSIS, DUAL TILT, HELIX ROOF", "147"],
@@ -48,6 +46,8 @@ class BomIntegrationTest(unittest.TestCase):
["515928", "FRONT SKIRT, HELIX ROOF", "126"],
["517871", "TRAY, LEADING, HELIX ROOF, RIVETED VERSION", "67"],
["518477", "WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS", "100"],
["521794", "DEFLECTOR, LH, HELIX ROOF V1.1", "30"],
["521795", "DEFLECTOR, RH, HELIX ROOF V1.1", "30"],
["Contractor Supplied", "Ballast Blocks", "608"],
["TBD", "Anchors", "86"],
["TBD", "Modules", "252"]
@@ -82,8 +82,6 @@ class BomIntegrationTest(unittest.TestCase):
expected = [
['512200', 'CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 352MM ^ 2', '540'],
['513833', 'TRAY, LINK, HELIX ROOF', '75'], # TODO: should be 73 for part perfect bom
['513841', 'DEFLECTOR, LH, HELIX ROOF', '20'],
['513842', 'DEFLECTOR, RH, HELIX ROOF', '20'],
['513843', 'PLATE, ANCHOR, HELIX ROOF', '114'],
['513844', 'TRAY, OPTIONAL BALLAST, HELIX ROOF', '17'],
['514056', 'BASE, CHASSIS, DUAL TILT, HELIX ROOF', '148'],
@@ -93,6 +91,8 @@ class BomIntegrationTest(unittest.TestCase):
['515928', 'FRONT SKIRT, HELIX ROOF', '130'],
['517871', 'TRAY, LEADING, HELIX ROOF, RIVETED VERSION', '69'],
['518477', 'WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS', '125'],
["521794", "DEFLECTOR, LH, HELIX ROOF V1.1", "20"],
["521795", "DEFLECTOR, RH, HELIX ROOF V1.1", "20"],
['Contractor Supplied', 'Ballast Blocks', '358'],
['TBD', 'Anchors', '114'],
['TBD', 'Modules', '264']
@@ -126,8 +126,6 @@ class BomIntegrationTest(unittest.TestCase):
expected = [
['512200', 'CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 352MM ^ 2', '330'],
['513833', 'TRAY, LINK, HELIX ROOF', '45'], # 45 is perfect value for this bom
['513841', 'DEFLECTOR, LH, HELIX ROOF', '36'],
['513842', 'DEFLECTOR, RH, HELIX ROOF', '36'],
['513843', 'PLATE, ANCHOR, HELIX ROOF', '67'],
['513844', 'TRAY, OPTIONAL BALLAST, HELIX ROOF', '13'],
['514056', 'BASE, CHASSIS, DUAL TILT, HELIX ROOF', '102'],
@@ -137,6 +135,8 @@ class BomIntegrationTest(unittest.TestCase):
['515928', 'FRONT SKIRT, HELIX ROOF', '88'],
['517871', 'TRAY, LEADING, HELIX ROOF, RIVETED VERSION', '53'],
['518477', 'WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS', '75'],
["521794", "DEFLECTOR, LH, HELIX ROOF V1.1", "36"],
["521795", "DEFLECTOR, RH, HELIX ROOF V1.1", "36"],
['Contractor Supplied', 'Ballast Blocks', '286'],
['TBD', 'Anchors', '67'],
['TBD', 'Modules', '160'],
@@ -171,8 +171,6 @@ class BomIntegrationTest(unittest.TestCase):
expected = [
['512200', 'CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 352MM ^ 2', '510'],
['513833', 'TRAY, LINK, HELIX ROOF', '73'], # TODO: should be 70 for part perfect bom
['513841', 'DEFLECTOR, LH, HELIX ROOF', '24'],
['513842', 'DEFLECTOR, RH, HELIX ROOF', '24'],
['513843', 'PLATE, ANCHOR, HELIX ROOF', '94'],
['513844', 'TRAY, OPTIONAL BALLAST, HELIX ROOF', '28'],
['514056', 'BASE, CHASSIS, DUAL TILT, HELIX ROOF', '140'],
@@ -182,6 +180,8 @@ class BomIntegrationTest(unittest.TestCase):
['515928', 'FRONT SKIRT, HELIX ROOF', '120'],
['517871', 'TRAY, LEADING, HELIX ROOF, RIVETED VERSION', '64'],
['518477', 'WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS', '100'],
["521794", "DEFLECTOR, LH, HELIX ROOF V1.1", "24"],
["521795", "DEFLECTOR, RH, HELIX ROOF V1.1", "24"],
['Contractor Supplied', 'Ballast Blocks', '560'],
['TBD', 'Anchors', '94'],
['TBD', 'Modules', '244'],

View File

@@ -10,6 +10,7 @@ from helix.constants import sql_constant
from helix.constants.anchor_type import AnchorType
from helix.constants.inverter_type import InverterType
from helix.constants.system_type import SystemType
from helix.constants.module_type import ModuleType
from helix.constants.version import version
from helix.models.sql.power_stations import PowerStation
from test.integration.integration_test_helpers import *
@@ -125,29 +126,32 @@ class FullUserFlowTest(unittest.TestCase):
eq_(self.browser._response.headers['Content-Disposition'], 'attachment; filename=test_project_name_result.txt')
def test_downloading_coordinates_csv(self):
with open('test/fixtures/expected_dual_tilt_coordinates.csv', 'r', newline='') as csv_file:
csv_content = csv_file.read()
self.browser.fill('project_name', 'Test Project Name')
self.browser.fill('building_width', '450')
self.browser.fill('building_height', '35')
self.browser.fill('building_length', '500')
self.browser.fill('wind_speed', '110')
self.browser.fill('exposure_category', 'B')
self.browser.fill('ballast_block_weight', '14')
self.browser.fill('building_parapet_height', '5')
self.browser.fill('max_system_pressure', '10')
self.browser.fill('system_type', SystemType.dualTilt.value)
self.browser.fill('anchor_type', AnchorType.OMG_PowerGrip_Plus.value)
self.browser.fill('design_spectral_response', '1.5')
#with open('test/fixtures/expected_dual_tilt_big_spacing.txt', 'r', newline='') as csv_file:
with open('test/fixtures/expected_small_dual_tilt.txt', 'r', newline='') as csv_file:
csv_content = csv_file.read()
self.browser.fill('project_name', 'Test Project Name')
self.browser.fill('building_width', '450')
self.browser.fill('building_height', '35')
self.browser.fill('building_length', '500')
self.browser.fill('wind_speed', '110')
self.browser.fill('exposure_category', 'B')
self.browser.fill('ballast_block_weight', '14')
self.browser.fill('building_parapet_height', '5')
self.browser.fill('max_system_pressure', '10')
self.browser.fill('system_type', SystemType.dualTilt.value)
self.browser.fill('anchor_type', AnchorType.OMG_PowerGrip_Plus.value)
self.browser.fill('design_spectral_response', '1.5')
self.browser.fill('module_type', ModuleType.Cell96.value)
self.advance_n_times(1)
self.attach_file('test/fixtures/input_dual_tilt_coordinates.csv')
self.advance_n_times(1)
self.attach_file('test/fixtures/input_small_dual_tilt.csv')
self.advance_n_times(1)
self.browser.visit('/download/')
self.browser.click_link_by_partial_text('Download AutoCAD import file')
eq_(self.browser.html, csv_content)
eq_(self.browser._response.headers['Content-Disposition'], 'attachment; filename=test_project_name_result.txt')
self.advance_n_times(1)
self.browser.visit('/download/')
self.browser.click_link_by_partial_text('Download AutoCAD import file')
eq_(self.browser.html, csv_content)
eq_(self.browser._response.headers['Content-Disposition'], 'attachment; filename=test_project_name_result.txt')
# def test_uploading_dxf_and_downloading_csv(self):
# self.browser.fill('project_name', 'Test Project Name')

View File

@@ -1,3 +1,4 @@
import time
from flask.ext.testing import LiveServerTestCase
import mockredis
from splinter import Browser
@@ -84,6 +85,7 @@ class PowerStationConfigurationDynamicFormTestCase(LiveServerTestCase):
eq_(self.browser.find_by_name('inverter-model').first.value, str(InverterType.SMA.default_value()))
select_inverter_brand(self.browser, brand=InverterBrand.DELTA.value)
time.sleep(1)
show_standalone_inverter_form(self.browser)
eq_(len(self.browser.find_by_css('#inverter-model option')), 3)

View File

@@ -5,6 +5,7 @@ from nose.tools import eq_
from helix.validators.csv_input_validator import CsvInputValidator
from helix.constants.system_type import SystemType
from helix.constants.module_type import ModuleType
from helix.constants.file_validation_error import FileValidationError, FileValidationMessage
@@ -94,3 +95,12 @@ class CsvInputValidatorTest(unittest.TestCase):
self.user_values.system_type.return_value = SystemType.dualTilt
cad_input = "A\tB\tC\tD\tE\r\nhandle\tblock\tA\t3\t1\r\n"
self.should_have_error(self.subject.validate(cad_input), FileValidationMessage.PanelTypeTooFewCornersDualTilt, None)
def test_reports_too_close_when_finds_panel_too_close_to_another_panel(self):
self.user_values.system_type.return_value = SystemType.dualTilt
self.user_values.module_type.return_value = ModuleType.Cell96
self.user_values.module_system_constants().tolerance = 0.1
self.user_values.module_system_constants().panel_spacing = (88.24, 62.0)
with open('test/fixtures/invalid_too_close.txt', 'r', newline='') as csv_file:
cad_input = csv_file.read()
self.should_have_error(self.subject.validate(cad_input), FileValidationMessage.PanelsTooClose , None)

16
watch.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
# Watches for changes in the files and passes to docker
# ignores the folders: node_modules, .git
cwd=$(pwd)
fswatch -0 -e node_modules -e .git -e env . | while read -d "" absPath
do
shortPath=""
shortPath=${absPath/$cwd/$shortPath}
echo "${shortPath}"
docker cp $absPath helix:project${shortPath}
done