window_cleaning_2026 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 18bfa9886c1fea88f5664c4b1daa7e48f14fb26d6bc7d176a7de68fcc665a270
4
+ data.tar.gz: 42692afe3202002c72ee21721e901af0a0d4a3b38ce498b6a8d803e506f03107
5
+ SHA512:
6
+ metadata.gz: 7ee5b9dffe9b51441cb5629509776e2f687e29643b3872c0aebe11374be5384c7349e284bd4e5eeb52b814472f25be4de24b7b9dff42bf256d74dd01833c49f6
7
+ data.tar.gz: 20f0987defb1c59a57eb930858bcd486c626a28a89a846f33ff0ec96dfb04b3cb7f6c0a122aee2ea6d869c4621b104e86e5e10ec713b7196025801cd78a6a6ba
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Binx Professional Cleaning
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # Window Cleaning 2026 — Commercial Cost Calculator
2
+
3
+ A Ruby gem for estimating commercial window cleaning costs. Built and maintained by [Binx Professional Cleaning](https://www.binx.ca/) — a WSIB-covered, fully insured commercial and residential cleaning company operating in Northern Ontario since 2013.
4
+
5
+ Binx serves over 500 commercial facilities across North Bay, Sudbury, Timmins, and Sault Ste. Marie, including office towers, medical centres, retail plazas, government buildings, and multi-unit residential complexes. This gem encodes the same pricing model Binx uses for internal quoting.
6
+
7
+ ---
8
+
9
+ ## Why This Exists
10
+
11
+ Commercial window cleaning pricing in Northern Ontario is opaque. Facility managers at hospitals like North Bay Regional Health Centre, municipal buildings in Greater Sudbury, shopping centres along Algonquin Avenue, and office towers on Lakeshore Drive all face the same problem: every vendor quotes differently — per window, per pane, per square foot, per hour — making apples-to-apples comparison nearly impossible.
12
+
13
+ This calculator gives facility managers a transparent baseline estimate before going to market. It accounts for the variables that actually drive commercial window cleaning costs in Northern Ontario:
14
+
15
+ - **Labour rates** — Ontario's prevailing wage for commercial cleaning technicians ($28–$38/hr in the North Bay–Sudbury corridor as of 2026)
16
+ - **Access method complexity** — ground-level squeegee work vs. ladder vs. boom lift vs. rope access vs. swing stage, each with different equipment, insurance, and crew-size requirements
17
+ - **Window type and count** — standard single pane, double pane (common in newer Sudbury office builds), floor-to-ceiling (downtown North Bay towers), storefront (retail along Main Street), and specialty glass (atriums, skylights)
18
+ - **Service scope** — interior only, exterior only, or full-service (interior + exterior)
19
+ - **Cleaning frequency** — one-time, quarterly, monthly, or weekly schedules, with volume discounts reflecting route optimization
20
+ - **Materials surcharge** — cleaning solution, squeegee blades, and consumables (8% of labour)
21
+ - **Profit margin** — adjustable percentage applied to the subtotal
22
+
23
+ ---
24
+
25
+ ## Installation
26
+
27
+ ```ruby
28
+ gem install window_cleaning_2026
29
+ ```
30
+
31
+ Or add to your Gemfile:
32
+
33
+ ```ruby
34
+ gem "window_cleaning_2026"
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Usage
40
+
41
+ ```ruby
42
+ require "window_cleaning_2026"
43
+
44
+ estimate = WindowCleaning2026::Calculator.calculate(
45
+ window_count: 120, # 120 windows
46
+ window_type: :double_pane, # double pane glass
47
+ access_method: :boom_lift, # boom lift required
48
+ service_type: :both, # interior + exterior
49
+ frequency: :quarterly, # quarterly schedule
50
+ labour_rate: 32.50, # $32.50/hr
51
+ margin_pct: 25.0 # 25% profit margin
52
+ )
53
+
54
+ puts estimate
55
+ # => {
56
+ # labour_cost: 643.50,
57
+ # materials_cost: 51.48,
58
+ # subtotal: 694.98,
59
+ # margin_amount: 173.75,
60
+ # final_price: 868.73,
61
+ # per_window_cost: 7.24
62
+ # }
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Pricing Model
68
+
69
+ The calculation follows this pipeline:
70
+
71
+ 1. **Base time per window** — each window type has a base cleaning duration in minutes (e.g., standard single pane = 4 min, specialty/atrium = 12 min)
72
+ 2. **Service multiplier** — interior-only work is 45% of full-service time; exterior-only is 55%
73
+ 3. **Access multiplier** — ground level (1.0×), ladder (1.4×), boom lift (2.2×), rope access (3.0×), swing stage (3.5×)
74
+ 4. **Total labour time** — `base × service × access × window_count`
75
+ 5. **Labour cost** — `(total_minutes / 60) × hourly_rate × frequency_discount`
76
+ 6. **Materials** — 8% of labour cost
77
+ 7. **Margin** — applied as a percentage of the subtotal (labour + materials)
78
+ 8. **Final price** — subtotal + margin
79
+
80
+ ### Access Method Details
81
+
82
+ | Method | Multiplier | Typical Use in Northern Ontario |
83
+ |--------|-----------|-------------------------------|
84
+ | Ground level | 1.0× | Single-storey retail along Algonquin Ave, strip malls |
85
+ | Ladder | 1.4× | Two-storey office buildings, North Bay downtown core |
86
+ | Boom lift | 2.2× | 3–6 storey buildings, Sudbury municipal complexes |
87
+ | Rope access | 3.0× | Tall structures without swing stage anchor points |
88
+ | Swing stage | 3.5× | High-rise — requires WSIB clearance, 2-person minimum crew |
89
+
90
+ ### Frequency Discounts
91
+
92
+ | Schedule | Discount | Notes |
93
+ |----------|----------|-------|
94
+ | One-time | 0% | No recurring commitment |
95
+ | Quarterly | 10% | Standard for most Northern Ontario commercial contracts |
96
+ | Monthly | 20% | Medical facilities, food service, high-traffic retail |
97
+ | Weekly | 30% | Rare — typically food processing or cleanroom facilities |
98
+
99
+ ---
100
+
101
+ ## Northern Ontario Market Context
102
+
103
+ Commercial window cleaning in Northern Ontario operates under conditions distinct from the GTA or Ottawa markets:
104
+
105
+ - **Seasonal constraints** — exterior cleaning is weather-dependent from roughly May through October; winter scheduling requires heated water systems and cold-weather PPE
106
+ - **Travel distance** — crews serving Timmins, Sault Ste. Marie, or Parry Sound from a North Bay base incur significant mobilization costs
107
+ - **WSIB requirements** — Ontario's Workplace Safety and Insurance Board requires clearance certificates for all commercial cleaning contractors; high-access work (boom lift, rope access, swing stage) carries additional classification premiums
108
+ - **Building stock** — Northern Ontario's commercial building stock skews older (1960s–1990s construction), with more single-pane and non-standard window configurations than newer southern Ontario builds
109
+ - **Labour market** — the North Bay–Sudbury corridor has a smaller labour pool for certified high-access technicians; rope access and swing stage crews are often shared across multiple contractors
110
+
111
+ ---
112
+
113
+ ## About Binx Professional Cleaning
114
+
115
+ [Binx Professional Cleaning](https://www.binx.ca/) has operated in Northern Ontario since 2013, providing commercial and residential cleaning services across the North Bay–Sudbury corridor. The company maintains WSIB coverage, full commercial liability insurance, and employs over 70 staff serving 500+ commercial facilities.
116
+
117
+ Services include commercial window cleaning, post-construction cleanup, office janitorial, medical facility sanitation, and specialized high-access exterior cleaning for buildings up to 12 storeys.
118
+
119
+ ---
120
+
121
+ ## License
122
+
123
+ MIT — see [LICENSE](LICENSE) for details.
124
+
125
+ ## Links
126
+
127
+ - **GitHub:** [DaveCookVectorLabs/window-cleaning-2026](https://github.com/DaveCookVectorLabs/window-cleaning-2026)
128
+ - **Documentation:** [window-cleaning-2026.readthedocs.io](https://window-cleaning-2026.readthedocs.io/)
129
+ - **PyPI:** [window-cleaning-2026](https://pypi.org/project/window-cleaning-2026/)
130
+ - **npm:** [@davecook/window-cleaning-2026](https://www.npmjs.com/package/@davecook/window-cleaning-2026)
131
+ - **Crates.io:** [window-cleaning-engine](https://crates.io/crates/window-cleaning-engine)
132
+ - **Maven Central:** [io.github.davecookvectorlabs:window-cleaning-engine](https://central.sonatype.com/artifact/io.github.davecookvectorlabs/window-cleaning-engine)
133
+ - **Docker Hub:** [davecook1985/window-cleaning-2026](https://hub.docker.com/r/davecook1985/window-cleaning-2026)
134
+ - **Dataset (Hugging Face):** [davecook1985/commercial-window-cleaning-costs-northern-ontario](https://huggingface.co/datasets/davecook1985/commercial-window-cleaning-costs-northern-ontario)
@@ -0,0 +1,84 @@
1
+ module WindowCleaning2026
2
+ # Base minutes per window by type — reflects typical commercial cleaning
3
+ # durations for Northern Ontario commercial facilities (office towers,
4
+ # retail storefronts, medical centres, multi-unit residential).
5
+ BASE_MINUTES = {
6
+ standard_single_pane: 4.0,
7
+ double_pane: 5.0,
8
+ floor_to_ceiling: 8.0,
9
+ storefront: 6.0,
10
+ specialty: 12.0,
11
+ }.freeze
12
+
13
+ # Service scope multiplier — interior glass takes less time than exterior
14
+ # due to reduced safety overhead and equipment setup.
15
+ SERVICE_MULTIPLIER = {
16
+ interior_only: 0.45,
17
+ exterior_only: 0.55,
18
+ both: 1.0,
19
+ }.freeze
20
+
21
+ # Access method cost multiplier — each step up in access difficulty adds
22
+ # equipment rental, safety certification, and crew-size overhead.
23
+ # Swing stage work in Northern Ontario typically requires WSIB clearance
24
+ # and a minimum two-person crew.
25
+ ACCESS_MULTIPLIER = {
26
+ ground_level: 1.0,
27
+ ladder: 1.4,
28
+ boom_lift: 2.2,
29
+ rope_access: 3.0,
30
+ swing_stage: 3.5,
31
+ }.freeze
32
+
33
+ # Frequency discount — recurring schedules reduce per-visit cost through
34
+ # route optimization and retained building familiarity.
35
+ FREQUENCY_DISCOUNT = {
36
+ one_time: 1.0,
37
+ quarterly: 0.90,
38
+ monthly: 0.80,
39
+ weekly: 0.70,
40
+ }.freeze
41
+
42
+ MATERIALS_RATE = 0.08
43
+
44
+ class Calculator
45
+ # Calculate a commercial window cleaning cost estimate.
46
+ #
47
+ # @param window_count [Integer] total windows (must be > 0)
48
+ # @param window_type [Symbol] one of BASE_MINUTES keys
49
+ # @param access_method [Symbol] one of ACCESS_MULTIPLIER keys
50
+ # @param service_type [Symbol] one of SERVICE_MULTIPLIER keys
51
+ # @param frequency [Symbol] one of FREQUENCY_DISCOUNT keys
52
+ # @param labour_rate [Float] hourly wage in CAD (must be > 0)
53
+ # @param margin_pct [Float] profit margin percentage 0-100
54
+ # @return [Hash] detailed cost breakdown
55
+ def self.calculate(window_count:, window_type:, access_method:, service_type:, frequency:, labour_rate:, margin_pct:)
56
+ raise ArgumentError, "window_count must be positive" unless window_count.positive?
57
+ raise ArgumentError, "labour_rate must be positive" unless labour_rate.positive?
58
+ raise ArgumentError, "margin_pct must be 0-100" unless (0..100).cover?(margin_pct)
59
+
60
+ base = BASE_MINUTES.fetch(window_type)
61
+ service_m = SERVICE_MULTIPLIER.fetch(service_type)
62
+ access_m = ACCESS_MULTIPLIER.fetch(access_method)
63
+ freq_d = FREQUENCY_DISCOUNT.fetch(frequency)
64
+
65
+ time_per_window = base * service_m * access_m
66
+ total_minutes = time_per_window * window_count
67
+ labour_cost = (total_minutes / 60.0) * labour_rate * freq_d
68
+ materials_cost = labour_cost * MATERIALS_RATE
69
+ subtotal = labour_cost + materials_cost
70
+ margin_amount = subtotal * (margin_pct / 100.0)
71
+ final_price = subtotal + margin_amount
72
+ per_window_cost = final_price / window_count
73
+
74
+ {
75
+ labour_cost: labour_cost.round(2),
76
+ materials_cost: materials_cost.round(2),
77
+ subtotal: subtotal.round(2),
78
+ margin_amount: margin_amount.round(2),
79
+ final_price: final_price.round(2),
80
+ per_window_cost: per_window_cost.round(2),
81
+ }
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,3 @@
1
+ module WindowCleaning2026
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,5 @@
1
+ require_relative "window_cleaning_2026/calculator"
2
+ require_relative "window_cleaning_2026/version"
3
+
4
+ module WindowCleaning2026
5
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: window_cleaning_2026
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dave Cook
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-04-04 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: A lightweight cost-estimation engine for commercial window cleaning jobs.
13
+ Models labour rates, access-method difficulty (ground level, ladder, boom lift,
14
+ rope access, swing stage), service scope, cleaning frequency discounts, materials
15
+ surcharge, and profit margins. Built by Binx Professional Cleaning — a WSIB-covered,
16
+ fully insured commercial and residential cleaning company operating in North Bay
17
+ and Sudbury, Northern Ontario since 2013.
18
+ email: dave@binx.ca
19
+ executables: []
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - LICENSE
24
+ - README.md
25
+ - lib/window_cleaning_2026.rb
26
+ - lib/window_cleaning_2026/calculator.rb
27
+ - lib/window_cleaning_2026/version.rb
28
+ homepage: https://github.com/DaveCookVectorLabs/window-cleaning-2026
29
+ licenses:
30
+ - MIT
31
+ metadata:
32
+ homepage_uri: https://github.com/DaveCookVectorLabs/window-cleaning-2026
33
+ source_code_uri: https://github.com/DaveCookVectorLabs/window-cleaning-2026/tree/main/engines/ruby
34
+ documentation_uri: https://window-cleaning-2026.readthedocs.io/
35
+ bug_tracker_uri: https://github.com/DaveCookVectorLabs/window-cleaning-2026/issues
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.7.0
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubygems_version: 3.6.3
51
+ specification_version: 4
52
+ summary: Commercial window cleaning cost calculator for Northern Ontario facility
53
+ managers
54
+ test_files: []